git-svn-id: https://svn.microneil.com/svn/PKG-SNF-SDK-WIN/trunk@28 7d91e7c8-5a61-404e-b06a-95855fde9112master
setlocal | setlocal | ||||
set PATH=32bitdll;%PATH% | set PATH=32bitdll;%PATH% | ||||
set DISTDIR=SNFMultiSDK_Windows_3.2 | |||||
set DISTDIR=SNFMultiSDK_Windows_3.3 | |||||
set TEMPDIR=C:\TEMP | set TEMPDIR=C:\TEMP | ||||
set ZIPFILE=%DISTDIR%.zip | set ZIPFILE=%DISTDIR%.zip | ||||
set TEMPDIST=%TEMPDIR%\%DISTDIR% | set TEMPDIST=%TEMPDIR%\%DISTDIR% |
#region DLL Imports | #region DLL Imports | ||||
// Location of SNFMulti.dll. | // Location of SNFMulti.dll. | ||||
//const string SNFMULTI_DLL = "..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "Any CPU" | //const string SNFMULTI_DLL = "..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "Any CPU" | ||||
const string SNFMULTI_DLL = "..\\..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "x64 | |||||
//const string SNFMULTI_DLL = "..\\..\\..\\..\\32bitDll\\SNFMulti.dll"; // Set CPU type to "x86" | |||||
//const string SNFMULTI_DLL = "..\\..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "x64 | |||||
const string SNFMULTI_DLL = "..\\..\\..\\..\\32bitDll\\SNFMulti.dll"; // Set CPU type to "x86" | |||||
// int setThrottle(int Threads); /* Set scan thread limit. */ | // int setThrottle(int Threads); /* Set scan thread limit. */ | ||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "setThrottle", CallingConvention = CallingConvention.Winapi)] | [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "setThrottle", CallingConvention = CallingConvention.Winapi)] |
IMPORTANT!! | |||||
The libgcc_s_dw2-1.dll, libstdc++-6.dll, and snfmulti.dll from this | |||||
distribution _MUST_ be kept together. There are multiple versions of | |||||
libgcc_s_dw2-1.dll and libstdc++-6.dll. Other versions may not be | |||||
compatible with this distribution. | |||||
If you experience errors such as segmentation faults or "The | |||||
application failed to initialize" then the most likely reason is that | |||||
an incompatible version of libgcc_s_dw2-1.dll or libstdc++-6.dll is | |||||
being loaded by snfmulti.dll. | |||||
EXPORTS | |||||
closeScan @1 | |||||
getIPReputation @2 | |||||
getScanClassicLog @3 | |||||
getScanResult @4 | |||||
getScanXHeaders @5 | |||||
getScanXMLLog @6 | |||||
scanBuffer @7 | |||||
scanFile @8 | |||||
setThrottle @9 | |||||
shutdownSNF @10 | |||||
startupSNF @11 | |||||
startupSNFAuthenticated @12 | |||||
testIP @13 |
IMPORTANT!! | |||||
The libgcc_s_sjlj-1.dll and snfmulti.dll from this distribution _MUST_ | |||||
be kept together. There are multiple versions of | |||||
libgcc_s_sjlj-1.dll. Other versions may not be compatible with this | |||||
distribution. | |||||
If you experience errors such as segmentation faults or "The | |||||
application failed to initialize" then the most likely reason is that | |||||
an incompatible version of the libgcc_s_sjlj-1.dll is being loaded by | |||||
snfmulti.dll. | |||||
EXPORTS | |||||
closeScan @1 | |||||
getIPReputation @2 | |||||
getScanClassicLog @3 | |||||
getScanResult @4 | |||||
getScanXHeaders @5 | |||||
getScanXMLLog @6 | |||||
scanBuffer @7 | |||||
scanFile @8 | |||||
setThrottle @9 | |||||
shutdownSNF @10 | |||||
startupSNF @11 | |||||
startupSNFAuthenticated @12 | |||||
testIP @13 |
Copyright (c) 2010 ARM Research Laboratories | |||||
The c++ sample application is as simple as possible. | |||||
It demonstrates how an oem application would initialize the SNF engine | |||||
(providing authentication at run-time so it is not exposed to the end | |||||
user); exercise the IP and message scanning API (message scanned from | |||||
a buffer already loaded in the application); retrieve status information | |||||
from the SNF engine; and close down the SNF engine gracefully. | |||||
For simplicity this demonstration code does not use multiple threads. |
// main.cpp SNF-SDK-WIN CPP OEM Demonstration Code | |||||
// Copyright (C) 2009 ARM Research Labs, LLC | |||||
// | |||||
// This app simply exercises the API provided by snfmultidll. | |||||
#include <iostream> | |||||
#include <string> | |||||
#include "../include/snfmultidll.h" | |||||
using namespace std; | |||||
//// Setup the basics we need to run this test. | |||||
const string LicenseID = "licensid"; // SNF License ID can be passed | |||||
const string Authentication = "authenticationxx"; // directly or read from the | |||||
const string ConfigurationPath = "snf_engine.xml"; // configuration. OEMs go direct! | |||||
const unsigned int IPToTest = 0x0c22384e; // Same as IP 12.34.56.78 | |||||
const string SampleMessage = | |||||
"Received: from mx-out.example.com [12.34.56.78] (HELO Somebody)\r\n" | |||||
" by mx-in.example.com (nosuchserver v1.0) for nobody@example.com\r\n" | |||||
"From: <somebody@example.com>\r\n" | |||||
"To: <nobody@example.com>\r\n" | |||||
"Subject: Nothing to see here\r\n" | |||||
"\r\n" | |||||
"So this is the big thing that's not here to see.\r\n" | |||||
"I thought it would be more interesting than this.\r\n" | |||||
"\r\n" | |||||
"_M\r\n" | |||||
".\r\n"; | |||||
//// Here is a simple example. Startup, exercise the API, shut down. | |||||
//// Note that we're doing this in a very "C" style becuase the DLL API is C | |||||
int main() { | |||||
int Result = 0; | |||||
Result = startupSNF(const_cast<char*>(ConfigurationPath.c_str())); | |||||
// Result = startupSNFAuthenticated( | |||||
// const_cast<char*>(ConfigurationPath.c_str()), | |||||
// const_cast<char*>(LicenseID.c_str()), | |||||
// const_cast<char*>(Authentication.c_str()) | |||||
// ); | |||||
cout << "Started with config " << ConfigurationPath << " Result: " << Result << endl; | |||||
// IP tests can be done asynchrounously - they do not have to be part of any particular scan. | |||||
Result = testIP(IPToTest); | |||||
cout << "IP test result: " << Result << endl; | |||||
double IPReputation = getIPReputation(IPToTest); | |||||
cout << "IP Reputation: " << IPReputation << endl; | |||||
// Messgae scans happen in a scan, read, close cycle as shown inside this loop. | |||||
const int NumberOfScans = 10; | |||||
for(int i = 0; i < NumberOfScans; i++) { | |||||
// Show how the IP reputation changes over time. | |||||
double IPReputation = getIPReputation(IPToTest); | |||||
cout << "IP Reputation: " << IPReputation << endl; | |||||
// Scan a message from a buffer. | |||||
int SetupTime = 12; | |||||
int ScanHandle = 0; | |||||
unsigned char* MsgBuffer = (unsigned char*) SampleMessage.c_str(); | |||||
unsigned int MsgBufferLength = (unsigned int) SampleMessage.length(); | |||||
ScanHandle = scanBuffer(MsgBuffer, MsgBufferLength, "TestMessage", SetupTime); | |||||
cout << "Scan Handle: " << ScanHandle << endl; | |||||
// Retrieve the X-Headers for the scan. | |||||
char* XHeadersBuffer = 0; | |||||
int XHeadersLength = 0; | |||||
int ScanResult = 0; | |||||
ScanResult = getScanXHeaders(ScanHandle, &XHeadersBuffer, &XHeadersLength); | |||||
string XHeaders(XHeadersBuffer); | |||||
// Close the scan. | |||||
Result = closeScan(ScanHandle); | |||||
cout << "Scan Close Result: " << Result << endl; | |||||
// X- headers were captured in a string BEFORE closing the scan so we can | |||||
// use them here. | |||||
cout << "Scan result code: " << ScanResult << endl; | |||||
cout << "Scan X- headers: " << XHeaders << endl; | |||||
} | |||||
// Now that all scanning is done we shut down. | |||||
Result = shutdownSNF(); | |||||
return Result; | |||||
} |
<html> | |||||
<head> | |||||
<title>C:\M\Projects\MessageSniffer\PKG-SNF-SDK-WIN_Work\PKG-SNF-SDK-WIN\CPPSample\main.cpp</title> | |||||
<style> | |||||
body { background-color: #ffffff; font-family: "Courier New"; font-size:10.0pt; font-style: normal; font-weight: normal; text-decoration: none; } | |||||
.se2 { color: #000000; background-color: #ffffff; } /* Window Text */ | |||||
.se17 { color: #800080; background-color: #ffffff; } /* Keyword */ | |||||
.se19 { color: #000080; background-color: #ffffff; } /* Number */ | |||||
.se20 { color: #008080; background-color: #ffffff; } /* String */ | |||||
.se22 { color: #808000; background-color: #ffffff; } /* Preprocessor */ | |||||
.se23 { color: #800000; background-color: #ffffff; } /* Punctuation */ | |||||
.se24 { color: #c04000; background-color: #ffffff; } /* Library Symbol */ | |||||
.se25 { color: #000000; background-color: #ffffff; } /* Operator */ | |||||
.se28 { color: #000000; background-color: #ffffff; font-weight: bolder; } /* Function */ | |||||
.se49 { color: #008000; background-color: #ffffff; font-style: italic; } /* Comment */ | |||||
.se50 { color: #004080; background-color: #ffffff; font-style: italic; } /* Comment */ | |||||
.se55 { color: #000000; background-color: #ffffff; } /* Window Text */ | |||||
.se57 { color: #000080; background-color: #ffffff; } /* Number */ | |||||
</style> | |||||
</head> | |||||
<body> | |||||
<pre> | |||||
<span class="se49">// main.cpp SNF-SDK-WIN CPP OEM Demonstration Code</span> | |||||
<span class="se49">// Copyright (C) 2009 ARM Research Labs, LLC</span> | |||||
<span class="se49">//</span> | |||||
<span class="se49">// This app simply exercises the API provided by snfmultidll.</span> | |||||
<span class="se22">#include</span><span class="se2"> </span><span class="se23"><</span><span class="se2">iostream</span><span class="se23">></span> | |||||
<span class="se22">#include</span><span class="se2"> </span><span class="se23"><</span><span class="se2">string</span><span class="se23">></span> | |||||
<span class="se22">#include</span><span class="se2"> </span><span class="se20">"../include/snfmultidll.h"</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se17">namespace</span><span class="se2"> </span><span class="se24">std</span><span class="se25">;</span> | |||||
<span class="se50">//// Setup the basics we need to run this test.</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se24">string</span><span class="se2"> </span><span class="se55">LicenseID</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"licensid"</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// SNF License ID can be passed</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se24">string</span><span class="se2"> </span><span class="se55">Authentication</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"authenticationxx"</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// directly or read from the</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se24">string</span><span class="se2"> </span><span class="se55">ConfigurationPath</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"snf_engine.xml"</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// configuration. OEMs go direct!</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">IPToTest</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se57">0x0c22384e</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// Same as IP 12.34.56.78</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se24">string</span><span class="se2"> </span><span class="se55">SampleMessage</span><span class="se2"> </span><span class="se25">=</span> | |||||
<span class="se2"> </span><span class="se20">"Received: from mx-out.example.com [12.34.56.78] (HELO Somebody)\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">" by mx-in.example.com (nosuchserver v1.0) for nobody@example.com\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"From: <somebody@example.com>\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"To: <nobody@example.com>\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"Subject: Nothing to see here\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"So this is the big thing that's not here to see.\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"I thought it would be more interesting than this.\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">"_M\r\n"</span> | |||||
<span class="se2"> </span><span class="se20">".\r\n"</span><span class="se25">;</span> | |||||
<span class="se50">//// Here is a simple example. Startup, exercise the API, shut down.</span> | |||||
<span class="se50">//// Note that we're doing this in a very "C" style becuase the DLL API is C</span> | |||||
<span class="se17">int</span><span class="se2"> </span><span class="se28">main</span><span class="se2">() </span><span class="se23">{</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">startupSNF</span><span class="se2">(</span><span class="se17">const_cast</span><span class="se25"><</span><span class="se17">char</span><span class="se25">*></span><span class="se2">(</span><span class="se55">ConfigurationPath</span><span class="se2">.</span><span class="se28">c_str</span><span class="se2">()))</span><span class="se25">;</span> | |||||
<span class="se49">// Result = startupSNFAuthenticated(</span> | |||||
<span class="se49">// const_cast<char*>(ConfigurationPath.c_str()),</span> | |||||
<span class="se49">// const_cast<char*>(LicenseID.c_str()),</span> | |||||
<span class="se49">// const_cast<char*>(Authentication.c_str())</span> | |||||
<span class="se49">// );</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"Started with config "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">ConfigurationPath</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">" Result: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// IP tests can be done asynchrounously - they do not have to be part of any particular scan.</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">testIP</span><span class="se2">(</span><span class="se55">IPToTest</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"IP test result: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">getIPReputation</span><span class="se2">(</span><span class="se55">IPToTest</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"IP Reputation: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Messgae scans happen in a scan, read, close cycle as shown inside this loop.</span> | |||||
<span class="se2"> </span><span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">NumberOfScans</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">10</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">for</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">i</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span><span class="se2"> </span><span class="se55">i</span><span class="se2"> </span><span class="se25"><</span><span class="se2"> </span><span class="se55">NumberOfScans</span><span class="se25">;</span><span class="se2"> </span><span class="se55">i</span><span class="se25">++</span><span class="se2">) </span><span class="se23">{</span> | |||||
<span class="se2"> </span><span class="se49">// Show how the IP reputation changes over time.</span> | |||||
<span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">getIPReputation</span><span class="se2">(</span><span class="se55">IPToTest</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"IP Reputation: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Scan a message from a buffer.</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">SetupTime</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">12</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">MsgBuffer</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> (</span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">char</span><span class="se25">*</span><span class="se2">) </span><span class="se55">SampleMessage</span><span class="se2">.</span><span class="se28">c_str</span><span class="se2">()</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">MsgBufferLength</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> (</span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">int</span><span class="se2">) </span><span class="se55">SampleMessage</span><span class="se2">.</span><span class="se28">length</span><span class="se2">()</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">scanBuffer</span><span class="se2">(</span><span class="se55">MsgBuffer</span><span class="se2">, </span><span class="se55">MsgBufferLength</span><span class="se2">, </span><span class="se20">"TestMessage"</span><span class="se2">, </span><span class="se55">SetupTime</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"Scan Handle: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Retrieve the X-Headers for the scan.</span> | |||||
<span class="se2"> </span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">XHeadersBuffer</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">XHeadersLength</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">ScanResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">getScanXHeaders</span><span class="se2">(</span><span class="se55">ScanHandle</span><span class="se2">, </span><span class="se25">&</span><span class="se55">XHeadersBuffer</span><span class="se2">, </span><span class="se25">&</span><span class="se55">XHeadersLength</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">string</span><span class="se2"> </span><span class="se28">XHeaders</span><span class="se2">(</span><span class="se55">XHeadersBuffer</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Close the scan.</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">closeScan</span><span class="se2">(</span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"Scan Close Result: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// X- headers were captured in a string BEFORE closing the scan so we can</span> | |||||
<span class="se2"> </span><span class="se49">// use them here.</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"Scan result code: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">ScanResult</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se24">cout</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se20">"Scan X- headers: "</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se55">XHeaders</span><span class="se2"> </span><span class="se25"><<</span><span class="se2"> </span><span class="se24">endl</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se23">}</span> | |||||
<span class="se2"> </span><span class="se49">// Now that all scanning is done we shut down.</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">shutdownSNF</span><span class="se2">()</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">return</span><span class="se2"> </span><span class="se55">Result</span><span class="se25">;</span> | |||||
<span class="se23">}</span> | |||||
</pre> | |||||
</body> | |||||
</html> |
Copyright (c) 2010 ARM Research Laboratories | |||||
The C# sample application is as simple as possible. | |||||
It demonstrates how an oem application would initialize the SNF engine | |||||
(providing authentication at run-time so it is not exposed to the end | |||||
user); exercise the IP and message scanning API (message scanned from | |||||
a buffer already loaded in the application); retrieve status information | |||||
from the SNF engine; and close down the SNF engine gracefully. | |||||
For simplicity this demonstration code does not use multiple threads. |
// main.cs SNF-SDK-WIN C# OEM Demonstration Code | |||||
// Copyright (C) 2009 ARM Research Labs, LLC | |||||
// | |||||
// This app simply exercises the API provided by snfmultidll. | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.IO; | |||||
using System.Collections; | |||||
using System.Runtime.InteropServices; | |||||
namespace SNFMultiDLLExampleCsharp | |||||
{ | |||||
class SNFMultiDLLExample | |||||
{ | |||||
#region DLL Imports | |||||
// Location of SNFMulti.dll. | |||||
//const string SNFMULTI_DLL = "..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "Any CPU" | |||||
//const string SNFMULTI_DLL = "..\\..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "x64 | |||||
const string SNFMULTI_DLL = "..\\..\\..\\..\\32bitDll\\SNFMulti.dll"; // Set CPU type to "x86" | |||||
// int setThrottle(int Threads); /* Set scan thread limit. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "setThrottle", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int setThrottle(int throttle); | |||||
// int startupSNF(char* Path); /* Start SNF with configuration. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "startupSNF", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int startupSNF([MarshalAs(UnmanagedType.LPStr)] string Path); | |||||
// EXP int startupSNFAuthenticated(char* Path, char* Lic, char* Auth); /* Start SNF with conf & auth. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "startupSNFAuthenticated", | |||||
CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int startupSNFAuthenticated( | |||||
[MarshalAs(UnmanagedType.LPStr)] string Path, | |||||
[MarshalAs(UnmanagedType.LPStr)] string Lic, | |||||
[MarshalAs(UnmanagedType.LPStr)] string Auth); | |||||
// int shutdownSNF(); /* Shutdown SNF. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "shutdownSNF", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int shutdownSNF(); | |||||
// int testIP(unsigned long int IPToCheck); /* Test the IP for a GBUdb range. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "testIP", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int testIP(ulong IPToCheck); | |||||
// double getIPReputation(unsigned long int IPToCheck); /* Get reputation figure for IP. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getIPReputation", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern double getIPReputation(ulong IPToCheck); | |||||
// int scanBuffer(unsigned char* Bfr, int Length, char* Name, int Setup);/* Scan msgBuffer, name, setup time. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "scanBuffer", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int scanBuffer( | |||||
[MarshalAs(UnmanagedType.LPStr)] string Bfr, | |||||
int Length, | |||||
[MarshalAs(UnmanagedType.LPStr)] string Name, | |||||
int Setup); | |||||
// int scanFile(char* FilePath, int Setup); /* Scan msgFile, setup time. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "scanFile", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int scanFile([MarshalAs(UnmanagedType.LPStr)] string Path, int Setup); | |||||
// int getScanXHeaders(int ScanHandle, char** Bfr, int* Length); /* Get result & XHeaders. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanXHeaders", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int getScanXHeaders(int ScanHandle, | |||||
out IntPtr Bfr, | |||||
out int Length); | |||||
// int getScanXMLLog(int ScanHandle, char** Bfr, int* Length); /* Get result & XML Log. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanXMLLog", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int getScanXMLLog(int ScanHandle, | |||||
out IntPtr Bfr, | |||||
out int Length); | |||||
// int getScanClassicLog(int ScanHandle, char** Bfr, int* Length); /* Get result & Classic Log. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanClassicLog", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int getScanClassicLog(int ScanHandle, | |||||
out IntPtr Bfr, | |||||
out int Length); | |||||
// int getScanResult(int ScanHandle); /* Get just the scan result. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanResult", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int getScanResult(int ScanHandle); | |||||
// int closeScan(int ScanHandle); /* Close the scan result. */ | |||||
[DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "closeScan", CallingConvention = CallingConvention.Winapi)] | |||||
public static extern int closeScan(int ScanHandle); | |||||
#endregion | |||||
static void Main(string[] args) | |||||
{ | |||||
//// Setup the basics we need to run this test. | |||||
// const string LicenseID = "licensid"; // SNF License ID can be passed | |||||
// const string Authentication = "authenticationxx"; // directly or read from the | |||||
// configuration. OEMs go direct! | |||||
//const string ConfigurationPath = "..\\..\\snf_engine.xml"; // For "Any CPU" platform. | |||||
const string ConfigurationPath = "..\\..\\..\\snf_engine.xml"; // For "x86" or "x64" platforms. | |||||
const uint IPToTest = 0x0c22384e; // Same as IP 12.34.56.78 | |||||
const string SampleMessage = | |||||
"Received: from mx-out.example.com [12.34.56.78] (HELO Somebody)\r\n" + | |||||
" by mx-in.example.com (nosuchserver v1.0) for nobody@example.com\r\n" + | |||||
"From: <somebody@example.com>\r\n" + | |||||
"To: <nobody@example.com>\r\n" + | |||||
"Subject: Nothing to see here\r\n" + | |||||
"\r\n" + | |||||
"So this is the big thing that's not here to see.\r\n" + | |||||
"I thought it would be more interesting than this.\r\n" + | |||||
"\r\n" + | |||||
"_M\r\n" + | |||||
".\r\n"; | |||||
//// Here is a simple example. Startup, exercise the API, shut down. | |||||
//// Note that we're doing this in a very "C" style becuase the DLL API is C | |||||
int Result = 0; | |||||
Result = startupSNF(ConfigurationPath); | |||||
//Result = startupSNFAuthenticated( | |||||
// ConfigurationPath, | |||||
// LicenseID, | |||||
// Authentication); | |||||
System.Console.WriteLine("Started with config " + ConfigurationPath + " Result: " + Result); | |||||
// IP tests can be done asynchrounously - they do not have to be part of any particular scan. | |||||
Result = testIP(IPToTest); | |||||
System.Console.WriteLine("IP test result: " + Result); | |||||
double IPReputation = getIPReputation(IPToTest); | |||||
System.Console.WriteLine("IP Reputation: " + IPReputation); | |||||
// Messgae scans happen in a scan, read, close cycle as shown inside this loop. | |||||
const int NumberOfScans = 10; | |||||
for(int i = 0; i < NumberOfScans; i++) { | |||||
// Show how the IP reputation changes over time. | |||||
IPReputation = getIPReputation(IPToTest); | |||||
System.Console.WriteLine("IP Reputation: " + IPReputation); | |||||
// Scan a message from a buffer. | |||||
int SetupTime = 12; | |||||
int ScanHandle = 0; | |||||
ScanHandle = scanBuffer(SampleMessage, SampleMessage.Length, "TestMessage", SetupTime); | |||||
System.Console.WriteLine("Scan Handle: " + ScanHandle); | |||||
// Retrieve the X-Headers for the scan. | |||||
IntPtr XHeadersPtr = IntPtr.Zero; | |||||
int XHeadersLength = 0; | |||||
int ScanResult = 0; | |||||
ScanResult = getScanXHeaders(ScanHandle, out XHeadersPtr, out XHeadersLength); | |||||
string XHeaders; | |||||
XHeaders = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(XHeadersPtr, XHeadersLength); | |||||
// Close the scan. | |||||
Result = closeScan(ScanHandle); | |||||
System.Console.WriteLine("Scan Close Result: " + Result); | |||||
// X- headers were captured in a string BEFORE closing the scan so we can | |||||
// use them here. | |||||
System.Console.WriteLine("Scan result code: " + ScanResult); | |||||
System.Console.WriteLine("Scan X- headers: " + XHeaders); | |||||
} | |||||
// Now that all scanning is done we shut down. | |||||
Result = shutdownSNF(); | |||||
} | |||||
} | |||||
} |
<html> | |||||
<head> | |||||
<title>C:\M\Projects\MessageSniffer\PKG-SNF-SDK-WIN_Work\PKG-SNF-SDK-WIN\CSSample\main.cs</title> | |||||
<style> | |||||
body { background-color: #ffffff; font-family: "Courier New"; font-size:10.0pt; font-style: normal; font-weight: normal; text-decoration: none; } | |||||
.se2 { color: #000000; background-color: #ffffff; } /* Window Text */ | |||||
.se17 { color: #800080; background-color: #ffffff; } /* Keyword */ | |||||
.se19 { color: #000080; background-color: #ffffff; } /* Number */ | |||||
.se20 { color: #008080; background-color: #ffffff; } /* String */ | |||||
.se22 { color: #808000; background-color: #ffffff; } /* Preprocessor */ | |||||
.se23 { color: #800000; background-color: #ffffff; } /* Punctuation */ | |||||
.se25 { color: #000000; background-color: #ffffff; } /* Operator */ | |||||
.se28 { color: #000000; background-color: #ffffff; font-weight: bolder; } /* Function */ | |||||
.se49 { color: #008000; background-color: #ffffff; font-style: italic; } /* Comment */ | |||||
.se50 { color: #004080; background-color: #ffffff; font-style: italic; } /* Comment */ | |||||
.se55 { color: #000000; background-color: #ffffff; } /* Window Text */ | |||||
.se57 { color: #000080; background-color: #ffffff; } /* Number */ | |||||
</style> | |||||
</head> | |||||
<body> | |||||
<pre> | |||||
<span class="se49">// main.cs SNF-SDK-WIN C# OEM Demonstration Code</span> | |||||
<span class="se49">// Copyright (C) 2009 ARM Research Labs, LLC</span> | |||||
<span class="se49">//</span> | |||||
<span class="se49">// This app simply exercises the API provided by snfmultidll.</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se25">;</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Collections</span><span class="se2">.</span><span class="se55">Generic</span><span class="se25">;</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Linq</span><span class="se25">;</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Text</span><span class="se25">;</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">IO</span><span class="se25">;</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Collections</span><span class="se25">;</span> | |||||
<span class="se17">using</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Runtime</span><span class="se2">.</span><span class="se55">InteropServices</span><span class="se25">;</span> | |||||
<span class="se17">namespace</span><span class="se2"> </span><span class="se55">SNFMultiDLLExampleCsharp</span> | |||||
<span class="se23">{</span> | |||||
<span class="se2"> </span><span class="se17">class</span><span class="se2"> </span><span class="se55">SNFMultiDLLExample</span> | |||||
<span class="se2"> </span><span class="se23">{</span> | |||||
<span class="se22">#region</span><span class="se2"> </span><span class="se55">DLL</span><span class="se2"> </span><span class="se55">Imports</span> | |||||
<span class="se2"> </span><span class="se49">// Location of SNFMulti.dll.</span> | |||||
<span class="se2"> </span><span class="se17">const</span><span class="se2"> </span><span class="se17">string</span><span class="se2"> </span><span class="se55">SNFMULTI_DLL</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"..\\..\\..\\64bitDll\\SNFMulti.dll"</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// Set CPU type to "Any CPU"</span> | |||||
<span class="se2"> </span><span class="se49">//const string SNFMULTI_DLL = "..\\..\\..\\..\\64bitDll\\SNFMulti.dll"; // Set CPU type to "x64</span> | |||||
<span class="se2"> </span><span class="se49">//const string SNFMULTI_DLL = "..\\..\\..\\..\\32bitDll\\SNFMulti.dll"; // Set CPU type to "x86"</span> | |||||
<span class="se2"> </span><span class="se49">// int setThrottle(int Threads); /* Set scan thread limit. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"setThrottle"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">setThrottle</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">throttle</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int startupSNF(char* Path); /* Start SNF with configuration. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"startupSNF"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">startupSNF</span><span class="se2">([</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Path</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// EXP int startupSNFAuthenticated(char* Path, char* Lic, char* Auth); /* Start SNF with conf & auth. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"startupSNFAuthenticated"</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">startupSNFAuthenticated</span><span class="se2">(</span> | |||||
<span class="se2"> [</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Path</span><span class="se2">,</span> | |||||
<span class="se2"> [</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Lic</span><span class="se2">,</span> | |||||
<span class="se2"> [</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Auth</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int shutdownSNF(); /* Shutdown SNF. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"shutdownSNF"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">shutdownSNF</span><span class="se2">()</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int testIP(unsigned long int IPToCheck); /* Test the IP for a GBUdb range. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"testIP"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">testIP</span><span class="se2">(</span><span class="se17">ulong</span><span class="se2"> </span><span class="se55">IPToCheck</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// double getIPReputation(unsigned long int IPToCheck); /* Get reputation figure for IP. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"getIPReputation"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se28">getIPReputation</span><span class="se2">(</span><span class="se17">ulong</span><span class="se2"> </span><span class="se55">IPToCheck</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span> | |||||
<span class="se2"> </span><span class="se49">// int scanBuffer(unsigned char* Bfr, int Length, char* Name, int Setup);/* Scan msgBuffer, name, setup time. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"scanBuffer"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">scanBuffer</span><span class="se2">(</span> | |||||
<span class="se2"> [</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">,</span> | |||||
<span class="se2"> [</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Name</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Setup</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int scanFile(char* FilePath, int Setup); /* Scan msgFile, setup time. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"scanFile"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">scanFile</span><span class="se2">([</span><span class="se28">MarshalAs</span><span class="se2">(</span><span class="se55">UnmanagedType</span><span class="se2">.</span><span class="se55">LPStr</span><span class="se2">)] </span><span class="se17">string</span><span class="se2"> </span><span class="se55">Path</span><span class="se2">, </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Setup</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int getScanXHeaders(int ScanHandle, char** Bfr, int* Length); /* Get result & XHeaders. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"getScanXHeaders"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanXHeaders</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">out</span><span class="se2"> </span><span class="se55">IntPtr</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">out</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int getScanXMLLog(int ScanHandle, char** Bfr, int* Length); /* Get result & XML Log. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"getScanXMLLog"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanXMLLog</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">out</span><span class="se2"> </span><span class="se55">IntPtr</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">out</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int getScanClassicLog(int ScanHandle, char** Bfr, int* Length); /* Get result & Classic Log. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"getScanClassicLog"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanClassicLog</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">out</span><span class="se2"> </span><span class="se55">IntPtr</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">,</span> | |||||
<span class="se2"> </span><span class="se17">out</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int getScanResult(int ScanHandle); /* Get just the scan result. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"getScanResult"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanResult</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// int closeScan(int ScanHandle); /* Close the scan result. */</span> | |||||
<span class="se2"> [</span><span class="se28">DllImport</span><span class="se2">(</span><span class="se55">SNFMULTI_DLL</span><span class="se2">, </span><span class="se55">CharSet</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CharSet</span><span class="se2">.</span><span class="se55">Auto</span><span class="se2">, </span><span class="se55">EntryPoint</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"closeScan"</span><span class="se2">, </span><span class="se55">CallingConvention</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">CallingConvention</span><span class="se2">.</span><span class="se55">Winapi</span><span class="se2">)]</span> | |||||
<span class="se2"> </span><span class="se17">public</span><span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">extern</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">closeScan</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se22">#endregion</span> | |||||
<span class="se2"> </span><span class="se17">static</span><span class="se2"> </span><span class="se17">void</span><span class="se2"> </span><span class="se28">Main</span><span class="se2">(</span><span class="se17">string</span><span class="se2">[] </span><span class="se55">args</span><span class="se2">)</span> | |||||
<span class="se2"> </span><span class="se23">{</span> | |||||
<span class="se2"> </span><span class="se50">//// Setup the basics we need to run this test.</span> | |||||
<span class="se2"> </span><span class="se49">// const string LicenseID = "licensid"; // SNF License ID can be passed</span> | |||||
<span class="se2"> </span><span class="se49">// const string Authentication = "authenticationxx"; // directly or read from the</span> | |||||
<span class="se2"> </span><span class="se49">// configuration. OEMs go direct!</span> | |||||
<span class="se2"> </span><span class="se17">const</span><span class="se2"> </span><span class="se17">string</span><span class="se2"> </span><span class="se55">ConfigurationPath</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se20">"..\\..\\snf_engine.xml"</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// For "Any CPU" platform.</span> | |||||
<span class="se2"> </span><span class="se49">//const string ConfigurationPath = "..\\..\\..\\snf_engine.xml"; // For "x86" or "x64" platforms.</span> | |||||
<span class="se2"> </span><span class="se17">const</span><span class="se2"> </span><span class="se17">uint</span><span class="se2"> </span><span class="se55">IPToTest</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se57">0x0c22384e</span><span class="se25">;</span><span class="se2"> </span><span class="se49">// Same as IP 12.34.56.78</span> | |||||
<span class="se2"> </span><span class="se17">const</span><span class="se2"> </span><span class="se17">string</span><span class="se2"> </span><span class="se55">SampleMessage</span><span class="se2"> </span><span class="se25">=</span> | |||||
<span class="se2"> </span><span class="se20">"Received: from mx-out.example.com [12.34.56.78] (HELO Somebody)\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">" by mx-in.example.com (nosuchserver v1.0) for nobody@example.com\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"From: <somebody@example.com>\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"To: <nobody@example.com>\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"Subject: Nothing to see here\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"So this is the big thing that's not here to see.\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"I thought it would be more interesting than this.\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">"_M\r\n"</span><span class="se2"> </span><span class="se25">+</span> | |||||
<span class="se2"> </span><span class="se20">".\r\n"</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se50">//// Here is a simple example. Startup, exercise the API, shut down.</span> | |||||
<span class="se2"> </span><span class="se50">//// Note that we're doing this in a very "C" style becuase the DLL API is C</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">startupSNF</span><span class="se2">(</span><span class="se55">ConfigurationPath</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">//Result = startupSNFAuthenticated(</span> | |||||
<span class="se2"> </span><span class="se49">// ConfigurationPath,</span> | |||||
<span class="se2"> </span><span class="se49">// LicenseID,</span> | |||||
<span class="se2"> </span><span class="se49">// Authentication);</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"Started with config "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">ConfigurationPath</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se20">" Result: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">Result</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// IP tests can be done asynchrounously - they do not have to be part of any particular scan.</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">testIP</span><span class="se2">(</span><span class="se55">IPToTest</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"IP test result: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">Result</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">getIPReputation</span><span class="se2">(</span><span class="se55">IPToTest</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"IP Reputation: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Messgae scans happen in a scan, read, close cycle as shown inside this loop.</span> | |||||
<span class="se2"> </span><span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">NumberOfScans</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">10</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">for</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">i</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span><span class="se2"> </span><span class="se55">i</span><span class="se2"> </span><span class="se25"><</span><span class="se2"> </span><span class="se55">NumberOfScans</span><span class="se25">;</span><span class="se2"> </span><span class="se55">i</span><span class="se25">++</span><span class="se2">) </span><span class="se23">{</span> | |||||
<span class="se2"> </span><span class="se49">// Show how the IP reputation changes over time.</span> | |||||
<span class="se2"> </span><span class="se55">IPReputation</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">getIPReputation</span><span class="se2">(</span><span class="se55">IPToTest</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"IP Reputation: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">IPReputation</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Scan a message from a buffer.</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">SetupTime</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">12</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">scanBuffer</span><span class="se2">(</span><span class="se55">SampleMessage</span><span class="se2">, </span><span class="se55">SampleMessage</span><span class="se2">.</span><span class="se55">Length</span><span class="se2">, </span><span class="se20">"TestMessage"</span><span class="se2">, </span><span class="se55">SetupTime</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"Scan Handle: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Retrieve the X-Headers for the scan.</span> | |||||
<span class="se2"> </span><span class="se55">IntPtr</span><span class="se2"> </span><span class="se55">XHeadersPtr</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">IntPtr</span><span class="se2">.</span><span class="se55">Zero</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">XHeadersLength</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">ScanResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">getScanXHeaders</span><span class="se2">(</span><span class="se55">ScanHandle</span><span class="se2">, </span><span class="se17">out</span><span class="se2"> </span><span class="se55">XHeadersPtr</span><span class="se2">, </span><span class="se17">out</span><span class="se2"> </span><span class="se55">XHeadersLength</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se17">string</span><span class="se2"> </span><span class="se55">XHeaders</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">XHeaders</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Runtime</span><span class="se2">.</span><span class="se55">InteropServices</span><span class="se2">.</span><span class="se55">Marshal</span><span class="se2">.</span><span class="se28">PtrToStringAnsi</span><span class="se2">(</span><span class="se55">XHeadersPtr</span><span class="se2">, </span><span class="se55">XHeadersLength</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// Close the scan.</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">closeScan</span><span class="se2">(</span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"Scan Close Result: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">Result</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se49">// X- headers were captured in a string BEFORE closing the scan so we can</span> | |||||
<span class="se2"> </span><span class="se49">// use them here.</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"Scan result code: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">ScanResult</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se55">System</span><span class="se2">.</span><span class="se55">Console</span><span class="se2">.</span><span class="se28">WriteLine</span><span class="se2">(</span><span class="se20">"Scan X- headers: "</span><span class="se2"> </span><span class="se25">+</span><span class="se2"> </span><span class="se55">XHeaders</span><span class="se2">)</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se23">}</span> | |||||
<span class="se2"> </span><span class="se49">// Now that all scanning is done we shut down.</span> | |||||
<span class="se2"> </span><span class="se55">Result</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se28">shutdownSNF</span><span class="se2">()</span><span class="se25">;</span> | |||||
<span class="se2"> </span><span class="se23">}</span> | |||||
<span class="se2"> </span><span class="se23">}</span> | |||||
<span class="se23">}</span> | |||||
</pre> | |||||
</body> | |||||
</html> |
20090707 Upgraded Engine to SNFMulti V3.0.8 (contains minor bug fixes). | |||||
20090704 Getting closer - new DLL, new features, a little polish. | |||||
NOTE: Beginning with this update this ChangeLog will only list hilights. | |||||
For more details check the logs at https://svn.microneil.com/websvn/ | |||||
* snfmulti.dll is now at version 3.0, engine 3.0.7 | |||||
* Used newer MinGW with improved optimizations | |||||
* Using newest SNF engine with several minor bug fixes | |||||
* Added startupSNFAuthenticated() so OEMs can protect SNF license info | |||||
* Added getIPReputation() to aid in converting GBUdb stats to weights | |||||
* Added C++ sample code | |||||
* Reorganized SNFMulti code base. | |||||
20090317 Work in progess toward SDK release. | |||||
* Included latest getRulebase.cmd and curl.exe | |||||
* Included SNFClient_readme.txt and SNFServer_readme.txt | |||||
* Included / updated SNFClient, and snf_engine.xml | |||||
* Added ReadMe.html - includes API documentation | |||||
* Added missing snf_ERROR_EXCEPTION to snfmultidll.h file | |||||
* Removed redundant #define EXP __declspec(dllexport) from snfmultidll.cpp | |||||
20080723 Version 2.9r3 - Engine 3.0 | |||||
* Compiled DLL using new SNF engine V3.0. | |||||
* Added snf_ERROR_EXCEPTION result (-3) to show when an exception occurred | |||||
during a call that could not be expressed with one of the normal SNF result | |||||
codes. | |||||
* Wraped DLLMain() functions in a try/catch to eat any exceptions. If an | |||||
exception occurs the function will return false; | |||||
* Added pre-allocation to result cache buffers to minimize heap allocation | |||||
during operations. The pre-allocated amount should be sufficient for all | |||||
cases. If it is not then the string objects will allocate more as needed. | |||||
* Changed snf_ERROR_UNKNOWN to snf_ERROR_EXCEPTION for startupSNF() and | |||||
shutdownSNF(). | |||||
* Wrapped testIP() in try/catch - now returns snf_ERROR_EXCEPTION if an | |||||
exception occurs. | |||||
* Wrapped getScanXHeaders() in try/catch - now returns snf_ERROR_EXCEPTION | |||||
if an exception occurs. | |||||
* Wrapped getScanXMLLog() in try/catch - now returns snf_ERROR_EXCEPTION | |||||
if an exception occurs. | |||||
* Wrapped getScanClassicLog() in try/catch - now returns snf_ERROR_EXCEPTION | |||||
if an exception occurs. | |||||
* Wrapped closeScan() in try/catch - now returns snf_ERROR_EXCEPTION | |||||
if an exception occurs. | |||||
// base64codec.cpp | |||||
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation | |||||
// See base64codec.hpp | |||||
//typedef vector<char> base64codec_buffer; | |||||
//typedef vector<char>::iterator base64codec_iterator; | |||||
#include "base64codec.hpp" | |||||
namespace base64codec { | |||||
const static char base64encode[65] = // Base64 encoding characters. | |||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||||
// The following table makes conversion fast because it's all lookups. The | |||||
// special value XX64 is used everywhere a bad byte is found in the table. | |||||
const static unsigned char XXXX = 0xFF; // Bad base64 character. | |||||
const static unsigned char PAD0 = 0xFE; // Pad base64 character. | |||||
const static unsigned char IGNR = 0xFD; // Ingoreable base64 character. | |||||
const static unsigned char STOP = 0xFC; // STOP -- all done. | |||||
// Note the special case '=' is used for pad. It is given the value 0xFE. | |||||
// Also the IGNR case is any whitespace (Tab, CR, NL) that can be ignored. | |||||
// The input to this table is the incoming byte. The output is either XX64 | |||||
// or a valid base64 numerical value. | |||||
const static unsigned char base64decode[256] = { | |||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,IGNR,IGNR,XXXX,XXXX,IGNR,XXXX,XXXX, // 0 | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // 1 | |||||
IGNR,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,0x3E,XXXX,XXXX,XXXX,0x3F, // 2 | |||||
0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,XXXX,XXXX,XXXX,PAD0,XXXX,XXXX, // 3 | |||||
XXXX,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 4 | |||||
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,XXXX,XXXX,XXXX,XXXX,XXXX, // 5 | |||||
XXXX,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, // 6 | |||||
0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,XXXX,XXXX,XXXX,XXXX,XXXX, // 7 | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // 8 | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // 9 | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // A | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // B | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // C | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // D | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX, // E | |||||
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX // F | |||||
}; | |||||
} // End namespace base64codec | |||||
using namespace base64codec; | |||||
//// to_base64 ///////////////////////////////////////////////////////////////// | |||||
void to_base64::convert(const unsigned char* bfr, const int len) { // Converts from a char buffer. | |||||
if(NULL == bfr || 0 >= len) { // If there's NULL or no length | |||||
BadConversion = true; // that was a bad conversion. | |||||
return; // lets get out of here. | |||||
} | |||||
int NewSize = (len / 3) * 4; // Base64 takes 4 bytes for every 3; | |||||
if(0 < len % 3) NewSize += 4; // If there are more, add an other 4; | |||||
reserve(NewSize); // Set aside enough memory for the job. | |||||
int cursor = 0; // Starting at zero chunk it off. | |||||
while(len > cursor) { | |||||
// Chunk off 4 bytes into an unsigned int for conversion. | |||||
enum EndGames { // Describe the end game for this | |||||
OneByte, // chunk as containing either one, | |||||
TwoBytes, // two, | |||||
ThreeBytes // or three bytes. | |||||
} EndGame; // We use this to code the end. | |||||
// Byte 0 | |||||
unsigned long REGISTER = 0; // Start with a clear register. | |||||
REGISTER += bfr[cursor]; REGISTER <<= 8; ++cursor; // Load Byte 0. | |||||
EndGame = OneByte; // We've added a byte. | |||||
// Byte 1 | |||||
if(len > cursor) { // If we've got bytes left. | |||||
REGISTER += bfr[cursor]; // load the next one and | |||||
++cursor; // move the cursor. | |||||
EndGame = TwoBytes; // We're up to 2 bytes. | |||||
} | |||||
REGISTER <<= 8; // Shift to the next byte. | |||||
// Byte 2 | |||||
if(len > cursor) { // If we've got bytes left. | |||||
REGISTER += bfr[cursor]; // load the next one and | |||||
++cursor; // move the cursor. | |||||
EndGame = ThreeBytes; // That's a full house. | |||||
} | |||||
// No shift this time, the register is full ;-) | |||||
// Now that we have 3 bytes and a characterization we can encode the | |||||
// base64 bytes into our vector. | |||||
const int SixBitMask = 0x0000003f; // This is how far to shift. | |||||
char code3 = base64encode[(REGISTER & SixBitMask)]; REGISTER >>= 6; // Encode four characters for this | |||||
char code2 = base64encode[(REGISTER & SixBitMask)]; REGISTER >>= 6; // three bytes. | |||||
char code1 = base64encode[(REGISTER & SixBitMask)]; REGISTER >>= 6; | |||||
char code0 = base64encode[(REGISTER & SixBitMask)]; | |||||
push_back(code0); // Push the first 2 encoded bytes onto | |||||
push_back(code1); // the vector in the original order. | |||||
switch(EndGame) { // Now handle the end game. | |||||
case OneByte: { // If the end contains one valid byte | |||||
push_back('='); // push back two = to indicate that | |||||
push_back('='); // the last two bytes are padding. | |||||
break; | |||||
} | |||||
case TwoBytes: { // If the end contains two valid bytes | |||||
push_back(code2); // push back one more code byte and | |||||
push_back('='); // push back only one = indicating one | |||||
break; // byte of padding. | |||||
} | |||||
case ThreeBytes: // If we had the full three bytes to | |||||
default: { // work with then we have no padding. | |||||
push_back(code2); // Push back the remaining two | |||||
push_back(code3); // code bytes to capture the full | |||||
break; // encoding. This also works | |||||
} // in the middle of the input. | |||||
} // That's it for the end game. | |||||
} // That's it for this chunk. | |||||
BadConversion = false; // If we get here we've done good. | |||||
} | |||||
to_base64::to_base64(const vector<unsigned char>& bfr) : // Converts from a base64buffer. | |||||
BadConversion(true) { // No conversion yet ;-) | |||||
convert(&bfr[0], bfr.size()); // Recast the pointer and do it. | |||||
} | |||||
to_base64::to_base64(const vector<char>& bfr) : // Converts from a base64codec buffer. | |||||
BadConversion(true) { // No conversion yet ;-) | |||||
convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // Do this to get it done. | |||||
} | |||||
to_base64::to_base64(const unsigned char* bfr, const int len) : // Converts from a uchar buffer. | |||||
BadConversion(true) { // No conversion yet ;-) | |||||
convert(bfr, len); // Do this to get it done. | |||||
} | |||||
to_base64::to_base64(const char* bfr, const int len) : // Converts from a char buffer. | |||||
BadConversion(true) { // No conversion yet ;-) | |||||
convert(reinterpret_cast<const unsigned char*>(bfr), len); // Do this to get it done. | |||||
} | |||||
to_base64::to_base64(const string& s) : // Converts from a c++ string. | |||||
BadConversion(true) { // No conversion yet ;-) | |||||
convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // Do this to get it done. | |||||
} | |||||
to_base64::to_base64(const char* s) : // Converts from a c string. | |||||
BadConversion(true) { // No conversion yet ;-) | |||||
convert(reinterpret_cast<const unsigned char*>(s), strlen(s)); // Do this to get it done. | |||||
} | |||||
bool to_base64::Bad() { // Look at the flag. | |||||
return BadConversion; | |||||
} | |||||
//// from_base64 /////////////////////////////////////////////////////////////// | |||||
unsigned char from_base64::NextSixBits( // Get the next base64 byte. | |||||
int& cursor, | |||||
const unsigned char* bfr, | |||||
const int len) { | |||||
while(len > cursor) { // Prepare to eat IGNR chars. | |||||
unsigned char c = base64decode[bfr[cursor]]; // Get the next 6 bits. | |||||
++cursor; // Move the cursor for next time. | |||||
if(IGNR == c) continue; // If we should ignore it, eat. | |||||
if(XXXX == c) return c; // If it's bad, return it. | |||||
return c; // If it's ordinary return it. | |||||
} // If we run out of bytes | |||||
return STOP; // return STOP | |||||
} | |||||
//// Since the BadConversion flag is set on construction, if we bail out | |||||
//// of the convert() for any reason then the conversion will be bad. | |||||
void from_base64::convert(const unsigned char* bfr, const int len) { // Converts bfr from base64 to plaintext. | |||||
if(NULL == bfr || 0 >= len) { return; } // If there's nothing to do return bad. | |||||
// Estimate our conversion buffer size. | |||||
int NewSize = len / 4 * 3; // Four bytes of base64 could be 3 bytes. | |||||
reserve(NewSize); // Reserve that much space for speed. | |||||
// Start the conversion process. | |||||
int cursor = 0; | |||||
while(len > cursor) { // Go through the buffer and convert. | |||||
int REGISTER = 0; // We will use these to convert as we | |||||
unsigned char LOOKUP = 0; // go through the data. | |||||
// First two base64 bytes | |||||
const int MakeRoomFor6Bits = 6; | |||||
LOOKUP = NextSixBits(cursor, bfr, len); // Grab the next six bits. | |||||
if(STOP == LOOKUP) { break; } // If we ran out here it's ok. | |||||
if(XXXX == LOOKUP) { return; } // If the byte is bad bail out! | |||||
REGISTER += LOOKUP; REGISTER <<= MakeRoomFor6Bits; // Shift that one into place. | |||||
LOOKUP = NextSixBits(cursor, bfr, len); // Grab the next six bits. | |||||
if(XXXX == LOOKUP || STOP == LOOKUP) { return; } // If bad or empty here bail out! | |||||
REGISTER += LOOKUP; // Load in the six bits. | |||||
// Now we have 12 bits so we can grab our first byte. | |||||
const int GetMS8OutOf12Bits = 4; | |||||
const int BottomFourBits = 0x0000000F; | |||||
push_back(REGISTER >> GetMS8OutOf12Bits); // Push back the converted byte. | |||||
REGISTER = (REGISTER & BottomFourBits) << MakeRoomFor6Bits; // Make room for the next 6 bits. | |||||
// Grab the next 6 bits. | |||||
LOOKUP = NextSixBits(cursor, bfr, len); // Grab the next six bits. | |||||
if(XXXX == LOOKUP || STOP == LOOKUP) { return; } // If bad or empty here bail out! | |||||
if(PAD0 == LOOKUP) { break; } // If we've come to a pad we're done! | |||||
REGISTER += LOOKUP; // Load in the six bits. | |||||
// Now we have 10 bits so we can grab our Second byte. | |||||
const int GetMS8OutOf10Bits = 2; | |||||
const int BottomTwoBits = 0x00000003; | |||||
push_back(REGISTER >> GetMS8OutOf10Bits); // Push back the converted byte. | |||||
REGISTER = (REGISTER & BottomTwoBits) << MakeRoomFor6Bits; // Make room for the next 6 bits. | |||||
LOOKUP = NextSixBits(cursor, bfr, len); // Grab the final six bits. | |||||
if(XXXX == LOOKUP || STOP == LOOKUP) { return; } // If bad or empty here bail out! | |||||
if(PAD0 == LOOKUP) { break; } // If we've come to a pad we're done! | |||||
REGISTER += LOOKUP; // Load in the six bits. | |||||
// Now we should have our final 8 bits :-) | |||||
push_back(REGISTER); // push back the converted byte. | |||||
} | |||||
BadConversion = false; // If we get here we did ok. | |||||
} | |||||
from_base64::from_base64(const vector<unsigned char>& bfr) : // Converts from a base64buffer. | |||||
BadConversion(true) { // It's bad until we've done it. | |||||
convert(&bfr[0], bfr.size()); // Recast the pointer and do it. | |||||
} | |||||
from_base64::from_base64(const vector<char>& bfr) : // Converts from a buffer. | |||||
BadConversion(true) { // It's bad until we've done it. | |||||
convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // This is how we do it. | |||||
} | |||||
from_base64::from_base64(const string& s) : // Converts from a c++ string. | |||||
BadConversion(true) { // It's bad until we've done it. | |||||
convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // This is how we do it. | |||||
} | |||||
from_base64::from_base64(const char* s) : // Converts from a c_string. | |||||
BadConversion(true) { // It's bad until we've done it. | |||||
convert(reinterpret_cast<const unsigned char*>(s), strlen(s)); // This is how we do it. | |||||
} | |||||
bool from_base64::Bad() { // Look at the flag. | |||||
return BadConversion; | |||||
} | |||||
// base64codec.hpp | |||||
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation | |||||
// BASE64 encoder decoder objects extending vectors | |||||
#ifndef base64codec_included | |||||
#define base64codec_included | |||||
#include <vector> | |||||
#include <cstring> | |||||
#include <string> | |||||
using namespace std; | |||||
typedef vector<unsigned char> base64buffer; | |||||
class to_base64 : public base64buffer { // Converts binary data to base 64. | |||||
private: | |||||
bool BadConversion; // True if something went wrong. | |||||
void convert(const unsigned char* bfr, const int len); // Does the actual work. | |||||
public: | |||||
to_base64(const vector<unsigned char>& bfr); // Converts from a base64buffer. | |||||
to_base64(const vector<char>& bfr); // Converts from a buffer. | |||||
to_base64(const string& s); // Converts from a c++ string. | |||||
to_base64(const char* s); // Converts from a c string. | |||||
to_base64(const unsigned char* bfr, const int len); // Converts from a uchar buffer. | |||||
to_base64(const char* bfr, const int len); // Converts from a char buffer. | |||||
bool Bad(); | |||||
}; | |||||
class from_base64 : public base64buffer { // Convert base64 data to binary. | |||||
private: | |||||
bool BadConversion; // True if the conversion didn't go well. | |||||
unsigned char NextSixBits( // Helper for decoding & ingoring spaces. | |||||
int& cursor, | |||||
const unsigned char* bfr, | |||||
const int len); | |||||
void convert(const unsigned char* bfr, const int len); // Does the actual work. | |||||
public: | |||||
from_base64(const vector<unsigned char>& bfr); // Converts from a base64buffer. | |||||
from_base64(const vector<char>& bfr); // Converts from a buffer. | |||||
from_base64(const string& s); // Converts from a c++ string. | |||||
from_base64(const char*); // Converts from a c_string. | |||||
bool Bad(); // True if conversion wasn't complete. | |||||
}; | |||||
#endif |
// configuration.hpp | |||||
// | |||||
// (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
// See http://www.codedweller.com for details. | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
// | |||||
// What about this ============================================================= | |||||
// The configuration module provides a platform for reading configuration files | |||||
// (or string data) containing well-formed xml and mapping that data to program | |||||
// variables. | |||||
// The idea is to provide the ability for an object or application to provide | |||||
// a modular "configuration" object that models a hierarchical collection of | |||||
// "settings" that can be represented easily in code and in xml. | |||||
// | |||||
// The following is an example model of a configuration in code and that same | |||||
// configuration fully populated in xml. | |||||
// | |||||
// The code might look like this... | |||||
// | |||||
// int IntValue, DefaultInt = 3; | |||||
// double DblValue, DefaultDbl = 3.14159; | |||||
// bool BooleanValue, DefaultBool = false; | |||||
// string StringValue, DefaultString = "NoStringHere"; | |||||
// | |||||
// SpecialConfigurator : public ConfigurationHandler { // Create a special handler to build a list | |||||
// ... | |||||
// public: | |||||
// | |||||
// ConfigurationHandler& Startup(ConfigurationElement& E) { // This function returns a handy handler to | |||||
// return MyStartupConfigurationHandler; // (re) initialize this handler ;-) | |||||
// } | |||||
// | |||||
// void Operator()() { // Each time the configurator is called | |||||
// ... | |||||
// } | |||||
// | |||||
// int Attribute1; // these items are interpreted and added | |||||
// double Attribute2; // to the list. A ConfigurationHandler COULD | |||||
// string Attribute3; // do something entirely different though ;-) | |||||
// string Contents; | |||||
// ... | |||||
// } Special; | |||||
// | |||||
// ConfigurationElement SampleConfig("SampleConfiguration"); // Define a sample config (doc element) | |||||
// SampleConfig // Populate the SampleConfig | |||||
// .atStartCall(Special.Startup()) | |||||
// .Element("Integer", IntValue, DefaultInt).End() // Link an element to an int w/ default. | |||||
// .Element("Double", DblValue, DefaultDbl).End("Double") // Link an element to a dbl w/ default. | |||||
// .Element("String", StringValue, DefaultString).End("String") // Link an element to a string w/ default. | |||||
// .Element("ComplexElements") // Create a sub element. | |||||
// .Element("Complex1") // Sub element Complex1 has attributes. | |||||
// .Attribute("IntAtt", IntValue, DefaultInt) // Complex1 has an integer attribute. | |||||
// .Attribute("DblAtt", DblValue, DefaultDbl) // Complex1 has a dbl attribute. | |||||
// .Element("IntAtt", IntValue).End() // IntAtt can also be set by a sub element. | |||||
// .Element("DblAtt", DblValue).End() // DblAtt can also be set by a sub element. | |||||
// .End() // That's it for Complex1. | |||||
// .Element("Complex2") // Create the Complex2 sub element. | |||||
// .Attribute("C2I", IntValue, DefaultInt) // C2I attribute. | |||||
// .Attribute("C2D", DblValue) // C2D attribute - no default. | |||||
// .Attribute("C2S", StringValue, DefultString) // C2S attribute - string w/ default. | |||||
// .End("Complex2") // End of element throws if doesn't match. | |||||
// .Element("Complex3", Special.Contents) // Element 3 using a special configurator. | |||||
// .Attribute("A1", Special.Attribute1) // Set A1 and A2 and A3 and when the | |||||
// .Attribute("A2", Special.Attribute2) // element has been completed, Special() | |||||
// .Attribute("A3", Special.Attribute3) // will be called to record the entries. | |||||
// .atEndCall(Special) // Here's where we register the handler. | |||||
// .End() // Closing Complex3 to be ice. | |||||
// .End() // Closing ComplexElements to be nice. | |||||
// .End(); // Closing SampleConfiguration to be nice. | |||||
// | |||||
// The XML might look like this... | |||||
// | |||||
// <SampleConfiguration> | |||||
// <Integer>10</Integer> | |||||
// <Double>2.4</Double> | |||||
// <String>This is a sample string</String> | |||||
// <ComplexElements> | |||||
// <Complex1 IntAtt="4" DblAtt="2.1324"> | |||||
// <IntAtt>24</IntAtt> <!-- changed IntAtt --> | |||||
// </Complex1> | |||||
// <Complex2 C2I='3' C2D='5.14' C2S='Some "string" we like' /> | |||||
// <Complex3> stuff in here </Complex3> | |||||
// <Complex3> Another instance </Complex3> | |||||
// <Complex3> Each one gets passed to Special() on activation </Complex3> | |||||
// <Complex3> This way, Special() can build a list or some other </Complex3> | |||||
// <Complex3> interesting thing with all of these. </Complex3> | |||||
// <ComplexElements> | |||||
// </SampleConfiguration> | |||||
// | |||||
// Include This Header Once Only =============================================== | |||||
#ifndef configuration_included | |||||
#define configuration_included | |||||
#include <string> | |||||
#include <sstream> | |||||
#include <fstream> | |||||
#include <cstring> | |||||
#include <cstdlib> | |||||
#include <list> | |||||
using namespace std; | |||||
class ConfigurationElement; // Elements exist | |||||
class ConfigurationAttribute; // Attributes exist | |||||
class ConfigurationData; // Data exists | |||||
class ConfigurationTranslator; // Translators exist | |||||
class ConfigurationMnemonic; // Mnemonics exist | |||||
class Configurator; // Configurators exist | |||||
//// Configuration Element ///////////////////////////////////////////////////// | |||||
// | |||||
// Elements make up the core of a configuration. That is, a configuration is a | |||||
// tree of elements. Elements translate directly to well formed xml elements in | |||||
// a configuration file or string. | |||||
class ConfigurationElement { | |||||
private: | |||||
string myName; // Elements have a name. | |||||
// External important things I remember but don't touch... | |||||
ConfigurationElement* myParent; // They may have a parrent. | |||||
list<Configurator*> myStartConfigurators; // Call these when we start Interpret() | |||||
list<Configurator*> myEndConfigurators; // Call these when we finish Interpret() | |||||
// Internal / subordinate things I own and kill... | |||||
list<ConfigurationAttribute*> myAttributes; // They may have a list of attributes. | |||||
list<ConfigurationElement*> myElements; // They may have a list of sub-elements. | |||||
list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics. | |||||
list<ConfigurationTranslator*> myTranslators; // They may have a list of translators. | |||||
// During Interpret() operations we keep track of where we are seen... | |||||
int myLine; // Last line number I was seen on. | |||||
int myIndex; // Last char position I was seen on. | |||||
int myLength; // Last segment length. | |||||
bool myCleanFlag; // Keep track of initialization. | |||||
bool myInitOnInterpretFlag; // Initialize() at each Interpret()? | |||||
void runStartConfigurators(ConfigurationData& D); // Does what it says ;-) | |||||
void runEndConfigurators(ConfigurationData& D); // Does what it says ;-) | |||||
public: | |||||
ConfigurationElement(const char* Name); // Must be constructed with a name | |||||
ConfigurationElement(const string Name); // either c string or c++ string. | |||||
ConfigurationElement(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a | |||||
ConfigurationElement(const string Name, ConfigurationElement& Parent); // parrent. | |||||
// Upon desctruction an element will delete all subordinate objects: | |||||
// * All sub element objects. | |||||
// * All attribute objects. | |||||
// * All mnemonic objects. | |||||
// * All translator objects. | |||||
// It is important to use new when passing one of these objects to an | |||||
// element or attribute to prevent problems with the delete operation. | |||||
// NORMALLY these things would be created using factory methods on the | |||||
// element and attribute objects themselves - so be careful. | |||||
// It will not delete Configurators - they must | |||||
// be deleted elsewhere because they may have been | |||||
// re-used and this element wouldn't know about it ;-) | |||||
~ConfigurationElement(); // The descrutor clears and deletes all! | |||||
// Elements can be probed for some simple, useful things. | |||||
string Name(); // Get the name of this element. | |||||
ConfigurationElement& Parent(); // Get the parent of this element. | |||||
ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element. | |||||
// Note - if there is no parent (an element is the root) then it will | |||||
// return a reference to itself when Parent() is called. | |||||
int Line(); // Get the last line number. | |||||
int Index(); // Get the last data position. | |||||
int Length(); // Get the last length. | |||||
// Elements can contain either data or sub-elements. | |||||
ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name. | |||||
ConfigurationElement& Element(const string Name); // Add a new sub element by c++ string name. | |||||
//// Mapping element factory methods for convenience. | |||||
//// Root-Node elements are _usually_ empty and without attributes in xml | |||||
//// so we don't make any of that type of convenience constructor here. | |||||
// char* versions | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// string versions | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// End methods for heading back up the tree at the end of an element. | |||||
class EndNameDoesNotMatch {}; // Throw when End(name) doesn't match. | |||||
ConfigurationElement& End(); // Return this element's parent. | |||||
ConfigurationElement& End(const char* Name); // Check the name and return the parent | |||||
ConfigurationElement& End(const string Name); // if the name is correct - or throw! | |||||
// Elements can have attributes. | |||||
ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. | |||||
ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string. | |||||
//// Mapping Attribute factory methods for convenience. | |||||
// char* versions | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// string versions | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// Elements can Initialize() at each Interpret() call. | |||||
ConfigurationElement& setInitOnInterpret(); // Set the init on interpret flag. | |||||
// Elements can call external functions to aid in special operations | |||||
// such as building lists. | |||||
ConfigurationElement& atStartCall(Configurator& Functor); // Add an atStart call-back to this element. | |||||
ConfigurationElement& atEndCall(Configurator& Functor); // Add an atEnd call-back to this element. | |||||
// Extracting data from the element's contents is done with | |||||
// translators. A good set of primatives are built in, but the user | |||||
// can also make their own. If an Element is mapped to more than | |||||
// one then they are all called once the element's contents are | |||||
// collected. A translator takes the data provided by the element, | |||||
// converts it into the expected type, and sets one or more variables | |||||
// to the converted value. Usually - just one variable. | |||||
ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationElement& mapTo(string& x, string init = string("")); // Map to a string. | |||||
ConfigurationElement& mapTo(int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationElement& mapTo(double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationElement& mapTo(bool& x, bool init = false); // Map to a boolean. | |||||
// An Element's contents may use some special mnemonics to make a | |||||
// configuration easier to understand and less error prone. When the | |||||
// contents match a mnemnoic then the translation of the mnemonic is | |||||
// passed to the Translators instead of the raw contents. | |||||
ConfigurationElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings. | |||||
ConfigurationElement& Mnemonic(const char* name, const string value); // Add a mnemonic using c & c++ strings. | |||||
ConfigurationElement& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings. | |||||
ConfigurationElement& Mnemonic(const string name, const string value); // Add a mnemonic using c++ strings. | |||||
// The way data gets into an element tree is that it is Interpret()ed | |||||
// recursively. The data is loaded into a ConfigurationData object which | |||||
// is passed to the top Element. That element interpretes the data, moves | |||||
// the interpretation pointers, and passes the data on to it's subordinate | |||||
// elements in turn. They do the same recursively. When the last sub - | |||||
// element has had it's way with the data, the interpretation process is | |||||
// complete. The ConfigurationData object will contain the original data | |||||
// and a log of anything that happened during the interpretation process. | |||||
// | |||||
// Each time an element is asked to Interpret() data, it calls any atStart | |||||
// configurators, translates any attributes, then either translates it's | |||||
// contents or passes the data to it's children, then calls any atEnd | |||||
// configurators. | |||||
// | |||||
// To ensure that the correct default values are used the Initialize() is | |||||
// always called on all internal attributes and elements before any data is | |||||
// interpreted. To prevent this from being inefficient, a boolean flag is | |||||
// kept in each element to keep track of whether it is clean and if it is | |||||
// then the call to Initialize will simply return (skipping subordinate | |||||
// elements along the way). | |||||
// | |||||
// Interpret returns true if this object found itself at the current | |||||
// Data.Index and false if not. This helps keep the recursive parsing | |||||
// code simpler ;-) | |||||
void initialize(); // Reset all translators to defaults. | |||||
void notifyDirty(); // Set dirty (if translators change). | |||||
bool interpret(ConfigurationData& Data); // (re) Interpret this data. | |||||
}; | |||||
//// Configuration Attribute /////////////////////////////////////////////////// | |||||
// | |||||
// Attributes translate directly to well formed xml attributes (within the | |||||
// start tag of an element). | |||||
class ConfigurationAttribute { | |||||
private: | |||||
string myName; // Elements have a name. | |||||
ConfigurationElement& myParent; // They may have a parrent. | |||||
list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics. | |||||
list<ConfigurationTranslator*> myTranslators; // They may have a list of translators. | |||||
int myLine; // Last line number I was seen on. | |||||
int myIndex; // Last char position I was seen on. | |||||
int myLength; // Last segment length. | |||||
public: | |||||
ConfigurationAttribute(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a | |||||
ConfigurationAttribute(const string Name, ConfigurationElement& Parent); // parrent. | |||||
// Attributes delete their Mnemonics and Translators when they go. | |||||
// See Elements for similar warnings about objects provided to | |||||
// this object... you must use new to be safe, or better yet - stick to | |||||
// the built in factory methods ;-) | |||||
~ConfigurationAttribute(); // Crush, Kill, Destroy! | |||||
// Attributes can be probed for some simple, useful things. | |||||
string Name(); // Get the name of this attribute. | |||||
ConfigurationElement& Parent(); // Get the parent of this attribute. | |||||
int Line(); // Get the last line number. | |||||
int Index(); // Get the last data position. | |||||
int Length(); // Get the last length. | |||||
void notifyDirty(); // Attributes use this when they change. | |||||
// For convenience in building configurations, an Attribute offers | |||||
// some call-through methods to it's parrent Element. This allows for | |||||
// clear, concise .method() coding that mimics an outline of the | |||||
// configuration structure. | |||||
//// For switching back to the parent element and adding new sub-elements. | |||||
ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name. | |||||
ConfigurationElement& Element(const string Name); // Add a new sub element by c++ string name. | |||||
//// Mapping element factory methods for convenience. | |||||
//// Root-Node elements are _usually_ empty and without attributes in xml | |||||
//// so we don't make any of that type of convenience constructor here. | |||||
// char* versions | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// string versions | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationElement& Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// End methods for heading back up the tree at the end of an element. | |||||
ConfigurationElement& End(); // Return this element's parent. | |||||
ConfigurationElement& End(const char* Name); // Check the name and return the parent | |||||
ConfigurationElement& End(const string Name); // if the name is correct - or throw! | |||||
//// For adding new attributes to the parent element. | |||||
ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. | |||||
ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string. | |||||
//// Mapping Attribute factory methods for convenience. | |||||
// char* versions | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
// string versions | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
string& x, string init = string("")); // Map to a string. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
int& x, int init = 0, int radix = 0); // Map to an int. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
bool& x, bool init = false); // Map to a boolean. | |||||
//// Set Init On Interprete for the parent element. | |||||
ConfigurationElement& setInitOnInterpret(); // Set the init on interpret flag. | |||||
//// For adding configurators to the parent element. | |||||
ConfigurationElement& atStartCall(Configurator& Functor); // Add an atStart call-back to this element. | |||||
ConfigurationElement& atEndCall(Configurator& Functor); // Add an atEnd call-back to this element. | |||||
// Of course, the most useful thing about attributes is that they can | |||||
// be mapped to variables using translators. The same as those that | |||||
// apply to the parent element's contents. Here they are for use on this | |||||
// attribute. | |||||
ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute. | |||||
ConfigurationAttribute& mapTo(string& x, string init = string("")); // Map to a string. | |||||
ConfigurationAttribute& mapTo(int& x, int init, int radix = 0); // Map to an int. | |||||
ConfigurationAttribute& mapTo(double& x, double init = 0.0); // Map to a double. | |||||
ConfigurationAttribute& mapTo(bool& x, bool init = false); // Map to a boolean. | |||||
// Attributes can have mnemonics just like elements. | |||||
ConfigurationAttribute& Mnemonic(const char* name, const char* value); // Add a mnemonic using a c string. | |||||
ConfigurationAttribute& Mnemonic(const char* name, const string value); // Add a mnemonic using c & c++ strings. | |||||
ConfigurationAttribute& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings. | |||||
ConfigurationAttribute& Mnemonic(const string name, const string value); // Add a mnemonic using a c++ string. | |||||
// Attributes participate in the Interprete() task just like elements. | |||||
void initialize(); // Reset all translators to defaults. | |||||
bool interpret(ConfigurationData& Data); // (re) Interpret this data. | |||||
}; | |||||
//// Configuration Data //////////////////////////////////////////////////////// | |||||
// | |||||
// A ConfigurationData object holds on to the configuration source data and | |||||
// provideds a place to log any information about how the configuration was | |||||
// interpreted. It also creates and destroys a handy char[] to contain the | |||||
// data. To make this beastie easier to handle, we use the Named Constructor | |||||
// Idiom and hide the true constructor in the private section. | |||||
class ConfigurationData { // Configuration Data Source | |||||
private: | |||||
char* myDataBuffer; // The actual data buffer. | |||||
int myBufferSize; // Size of the current buffer. | |||||
int myIndex; // The current interpretation index. | |||||
int myLine; // Current line number. | |||||
public: | |||||
ConfigurationData(const char* FileName); // Constructor from c string file name. | |||||
ConfigurationData(const string FileName); // Constructor from c++ string file name. | |||||
ConfigurationData(const char* Data, int Length); // Raw constructor from text buffer. | |||||
~ConfigurationData(); // Destroys the internal buffer etc. | |||||
char Data(int Index); // Returns char from Data[Index] | |||||
int Index(); // Reads the current Index. | |||||
int Index(int i); // Changes the current Index. | |||||
int Line(); // Reads the current Line number. | |||||
int addNewLines(int Count); // Increments the Line number. | |||||
stringstream Log; // Convenient Interpret log. | |||||
}; | |||||
//// Configuration Translator ////////////////////////////////////////////////// | |||||
// | |||||
// A Translator converts the contents provided to it in string form into some | |||||
// other data type. The object here is a prototype for that, followed by a | |||||
// collection of the basic translators used for built-in mapTo()s. | |||||
class ConfigurationTranslator { // Translators exist | |||||
public: | |||||
virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings. | |||||
virtual void translate(const char* Value) = 0; // Pure virtual translator. | |||||
virtual void initialize() = 0; // Pure virtual initializer. | |||||
}; | |||||
class StringTranslator : public ConfigurationTranslator { | |||||
private: | |||||
string& myVariable; // Variable to map. | |||||
string myInitializer; // Initial/Default value. | |||||
public: | |||||
StringTranslator( // Construct this with | |||||
string& Variable, // the variable to map, | |||||
string Inititializer); // and the default value. | |||||
void translate(const char* Value); // Provide a translation method. | |||||
void initialize(); // Provide an initialization method. | |||||
}; | |||||
class IntegerTranslator : public ConfigurationTranslator { | |||||
private: | |||||
int& myVariable; // Variable to map. | |||||
int myInitializer; // Initial/Default value. | |||||
int myRadix; // Radix for strtol() | |||||
public: | |||||
IntegerTranslator( // Construct this with | |||||
int& Variable, // the variable to map, | |||||
int Inititializer, // and the default value. | |||||
int Radix); // For this one we also need a Radix. | |||||
void translate(const char* Value); // Provide a translation method. | |||||
void initialize(); // Provide an initialization method. | |||||
}; | |||||
class DoubleTranslator : public ConfigurationTranslator { | |||||
private: | |||||
double& myVariable; // Variable to map. | |||||
double myInitializer; // Initial/Default value. | |||||
public: | |||||
DoubleTranslator( // Construct this with | |||||
double& Variable, // the variable to map, | |||||
double Inititializer); // and the default value. | |||||
void translate(const char* Value); // Provide a translation method. | |||||
void initialize(); // Provide an initialization method. | |||||
}; | |||||
class BoolTranslator : public ConfigurationTranslator { | |||||
private: | |||||
bool& myVariable; // Variable to map. | |||||
bool myInitializer; // Initial/Default value. | |||||
public: | |||||
BoolTranslator( // Construct this with | |||||
bool& Variable, // the variable to map, | |||||
bool Inititializer); // and the default value. | |||||
void translate(const char* Value); // Provide a translation method. | |||||
void initialize(); // Provide an initialization method. | |||||
}; | |||||
//// Configuration Mnemonic //////////////////////////////////////////////////// | |||||
// | |||||
// A Mnemonic allows the actual contents of an element or attribute to be | |||||
// exchanged for a different "named" value to help eliminate "magic numbers" | |||||
// and "secret codes" from configurations. One way this might be used is to | |||||
// map an enumeration to the appropriate integer values, or things like YES and | |||||
// NO to boolean true and false (respectively) when turning on/off program | |||||
// options. | |||||
class ConfigurationMnemonic { // Mnemonics | |||||
private: | |||||
string myName; // What is the Mnemonic? | |||||
string myValue; // What is the translation? | |||||
public: | |||||
ConfigurationMnemonic(string Name, string Value); // To make one, provide both parts. | |||||
bool test(string Name); // Test to see if this Mnemonic matches. | |||||
string Value(); // If it does then we will need it's value. | |||||
}; | |||||
//// Configurator ////////////////////////////////////////////////////////////// | |||||
// | |||||
// A configurator is a "functor" or "closure" or "callback" that can be used to | |||||
// support sophisticated interpretation options. The most basic and necessary | |||||
// of these is support for list building. Consider an object created to contain | |||||
// a list of records where each record might be represented as a collection of | |||||
// attributes and elements. The object would have data elements mapped to the | |||||
// attributes and elements in the configuration and then control elements which | |||||
// are functors for initializing the list and storing new entries as they are | |||||
// completed. The object here is a pure virtual prototype. | |||||
class Configurator { // Configurators exist | |||||
public: | |||||
virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator. | |||||
virtual ~Configurator() {} // Virtual dtor keeps warnings away. | |||||
}; | |||||
//// Include our inline methods //////////////////////////////////////////////// | |||||
#include "configuration.inline.hpp" | |||||
//// Utilities ///////////////////////////////////////////////////////////////// | |||||
// SetTrueOnComplete Configurator ////////////////////////////////////////////// | |||||
class ConfiguratorSetTrueOnComplete : public Configurator { // Configurator set's a boolean true. | |||||
private: | |||||
bool* myBoolean; // The boolean to set. | |||||
public: | |||||
ConfiguratorSetTrueOnComplete(); // Must init to NULL for safety. | |||||
void setup(bool& Target); // Link to the target boolean. | |||||
void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation. | |||||
}; | |||||
#endif | |||||
// End Of Include Only Once | |||||
// configuration.inline.hpp | |||||
// | |||||
// (C) 2006-2009 MicroNeil Research Corporation. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
// See configuration.hpp for details | |||||
//// Configuration Element ///////////////////////////////////////////////////// | |||||
inline ConfigurationElement::ConfigurationElement(const char* Name) : // Construct with a cstring. | |||||
myName(string(Name)), | |||||
myParent(NULL), | |||||
myLine(0), | |||||
myIndex(0), | |||||
myLength(0), | |||||
myCleanFlag(true), | |||||
myInitOnInterpretFlag(false) { | |||||
} | |||||
inline ConfigurationElement::ConfigurationElement(const string Name) : // Construct with a c++ string. | |||||
myName(Name), | |||||
myParent(NULL), | |||||
myLine(0), | |||||
myIndex(0), | |||||
myLength(0), | |||||
myCleanFlag(true), | |||||
myInitOnInterpretFlag(false) { | |||||
} | |||||
inline ConfigurationElement::ConfigurationElement( // Construct sub element w/ cstring. | |||||
const char* Name, | |||||
ConfigurationElement& Parent) : | |||||
myName(string(Name)), | |||||
myParent(&Parent), | |||||
myLine(0), | |||||
myIndex(0), | |||||
myLength(0), | |||||
myCleanFlag(true), | |||||
myInitOnInterpretFlag(false) { | |||||
} | |||||
inline ConfigurationElement::ConfigurationElement( // Construct sub element w/ string. | |||||
const string Name, | |||||
ConfigurationElement& Parent) : | |||||
myName(Name), | |||||
myParent(&Parent), | |||||
myLine(0), | |||||
myIndex(0), | |||||
myLength(0), | |||||
myCleanFlag(true), | |||||
myInitOnInterpretFlag(false) { | |||||
} | |||||
inline string ConfigurationElement::Name() { return myName; } // Get the name of this element. | |||||
inline ConfigurationElement& ConfigurationElement::Parent() { // Get the parrent of this element. | |||||
if(NULL != myParent) { // If I have a parent | |||||
return (*myParent); // then I dereference and return it. | |||||
} // If I don't have a parent | |||||
return (*this); // then I return myself. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Parent( // Set the parrent of this element. | |||||
ConfigurationElement& Parent) { // Given this parent | |||||
myParent = &Parent; // I take and store it's address | |||||
return (*myParent); // then dereference and return it. | |||||
} | |||||
inline int ConfigurationElement::Line() { return myLine; } // Get the last line number. | |||||
inline int ConfigurationElement::Index() { return myIndex; } // Get the last data position. | |||||
inline int ConfigurationElement::Length() { return myLength; } // Get the last length. | |||||
inline void ConfigurationElement::notifyDirty() { myCleanFlag = false; } // Attributes do this when they change. | |||||
inline ConfigurationElement& ConfigurationElement::Element(const char* Name) { // Add a new sub element by c string name. | |||||
return Element(string(Name)); // Use the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Element(const string Name) { // Add a new sub element by c++ string name. | |||||
ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||||
Name, // name provided and | |||||
(*this)); // myself as the parent. | |||||
myElements.push_back(N); // Add it to the list. | |||||
return (*N); // Return the new element. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
return Element(string(Name), newTranslator); // Use the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init) { // Map to a string. | |||||
return Element(string(Name), x, init); // Use the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init, int radix) { // Map to an int. | |||||
return Element(string(Name), x, init, radix); // Use the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init) { // Map to a double. | |||||
return Element(string(Name), x, init); // Use the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init) { // Map to a boolean. | |||||
return Element(string(Name), x, init); // Use the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::End() { // Return this element's parent. | |||||
return Parent(); // Borrow Parent() | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::End(const char* Name) { // Check the name and return the parent | |||||
return End(string(Name)); // Borrow End(string) | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::End(const string Name) { // if the name is correct - or throw! | |||||
if(0 != Name.compare(myName)) { // If Name is not myName | |||||
throw EndNameDoesNotMatch(); // throw an exception! | |||||
} // If the names match then | |||||
return Parent(); // return the parent. | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationElement::Attribute( // Add an attribute using a cstring. | |||||
const char* Name) { // Given this cstring name | |||||
return Attribute(string(Name)); // Convert it to a string and borrow | |||||
} // Attribute(string) | |||||
inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
return Attribute(string(Name), newTranslator); // Borrow the string name version | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init) { // Map to a string. | |||||
return Attribute(string(Name), x, init); // Borrow the string name version | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init, int radix) { // Map to an int. | |||||
return Attribute(string(Name), x, init); // Borrow the string name version | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init) { // Map to a double. | |||||
return Attribute(string(Name), x, init); // Borrow the string name version | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init) { // Map to a boolean. | |||||
return Attribute(string(Name), x, init); // Borrow the string name version | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::setInitOnInterpret() { // Set the init on interpret flag. | |||||
myInitOnInterpretFlag = true; // Set the flag. | |||||
return(*this); // Dereference and return self. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::atStartCall( // Add an atStart call-back. | |||||
Configurator& Functor) { // Given this Functor, | |||||
myStartConfigurators.push_back(&Functor); // add it to my atStart list then | |||||
return(*this); // dereference and return myself. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::atEndCall( // Add an atEnd call-back. | |||||
Configurator& Functor) { // Given this Functor, | |||||
myEndConfigurators.push_back(&Functor); // add it to my atEnd list then | |||||
return(*this); // dereference and return myself. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c strings. | |||||
const char* name, const char* value) { // Given char* and char* | |||||
return Mnemonic(string(name), string(value)); // make strings and borrow that method. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings. | |||||
const char* name, const string value) { // Given char* and string | |||||
return Mnemonic(string(name), value); // make strings and borrow that method. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings. | |||||
const string name, const char* value) { // Given string and char* | |||||
return Mnemonic(name, string(value)); // make strings and borrow that method. | |||||
} | |||||
inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c++ strings. | |||||
const string name, const string value) { // Givent string and string | |||||
ConfigurationMnemonic* N = // Create a new Mnemonic | |||||
new ConfigurationMnemonic(name, value); // using the values provided, | |||||
myMnemonics.push_back(N); // add it to my list, then | |||||
return(*this); // dereference and return myself. | |||||
} | |||||
//// Configuration Attribute /////////////////////////////////////////////////// | |||||
inline ConfigurationAttribute::ConfigurationAttribute( // Attributes are constructed with a | |||||
const char* Name, ConfigurationElement& Parent) : // Name and a Parent. | |||||
myName(string(Name)), // We convert the name to a string. | |||||
myParent(Parent), // We just grab the parent. | |||||
myLine(0), // Everything else gets zeroed. | |||||
myIndex(0), | |||||
myLength(0) { | |||||
} | |||||
inline ConfigurationAttribute::ConfigurationAttribute( // Attributes are constrictued with a | |||||
const string Name, ConfigurationElement& Parent) : // Name and a Parent. | |||||
myName(Name), // We grab them and zero the rest. | |||||
myParent(Parent), | |||||
myLine(0), | |||||
myIndex(0), | |||||
myLength(0) { | |||||
} | |||||
inline string ConfigurationAttribute::Name() { // Get the name of this attribute. | |||||
return myName; | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Parent() { // Get the parent of this attribute. | |||||
return myParent; | |||||
} | |||||
inline int ConfigurationAttribute::Line() { // Get the last line number. | |||||
return myLine; | |||||
} | |||||
inline int ConfigurationAttribute::Index() { // Get the last data position. | |||||
return myIndex; | |||||
} | |||||
inline int ConfigurationAttribute::Length() { // Get the last length. | |||||
return myLength; | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c string name. | |||||
const char* Name) { | |||||
return myParent.Element(Name); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c++ string name. | |||||
const string Name) { | |||||
return myParent.Element(Name); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
return myParent.Element(Name, newTranslator); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init) { // Map to a string. | |||||
return myParent.Element(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init, int radix) { // Map to an int. | |||||
return myParent.Element(Name, x, init, radix); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init) { // Map to a double. | |||||
return myParent.Element(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init) { // Map to a boolean. | |||||
return myParent.Element(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
return myParent.Element(Name, newTranslator); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
string& x, string init) { // Map to a string. | |||||
return myParent.Element(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
int& x, int init, int radix) { // Map to an int. | |||||
return myParent.Element(Name, x, init, radix); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
double& x, double init) { // Map to a double. | |||||
return myParent.Element(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
bool& x, bool init) { // Map to a boolean. | |||||
return myParent.Element(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::End() { // Return this element's parent. | |||||
return myParent.End(); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::End(const char* Name) { // Check the name and return the parent | |||||
return myParent.End(Name); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::End(const string Name) { // if the name is correct - or throw! | |||||
return myParent.End(Name); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a cstring. | |||||
const char* Name) { | |||||
return myParent.Attribute(Name); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a c++ string. | |||||
const string Name) { | |||||
return myParent.Attribute(Name); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
return myParent.Attribute(Name, newTranslator); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
string& x, string init) { // Map to a string. | |||||
return myParent.Attribute(Name, x, init); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
int& x, int init, int radix) { // Map to an int. | |||||
return myParent.Attribute(Name, x, init, radix); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
double& x, double init) { // Map to a double. | |||||
return myParent.Attribute(Name, x, init); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const char* Name, // requires a name, of course, | |||||
bool& x, bool init) { // Map to a boolean. | |||||
return myParent.Attribute(Name, x, init); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
return myParent.Attribute(Name, newTranslator); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
string& x, string init) { // Map to a string. | |||||
return myParent.Attribute(Name, x, init); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
int& x, int init, int radix) { // Map to an int. | |||||
return myParent.Attribute(Name, x, init, radix); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
double& x, double init) { // Map to a double. | |||||
return myParent.Attribute(Name, x, init); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
const string Name, // requires a name, of course, | |||||
bool& x, bool init) { // Map to a boolean. | |||||
return myParent.Attribute(Name, x, init); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::setInitOnInterpret() { // Set the init on interpret flag. | |||||
return myParent.setInitOnInterpret(); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::atStartCall( // Add an atStart call-back to this element. | |||||
Configurator& Functor) { | |||||
return myParent.atStartCall(Functor); | |||||
} | |||||
inline ConfigurationElement& ConfigurationAttribute::atEndCall( // Add an atEnd call-back to this element. | |||||
Configurator& Functor) { | |||||
return myParent.atEndCall(Functor); | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c strings. | |||||
const char* name, const char* value) { // Given char* and char* | |||||
return Mnemonic(string(name), string(value)); // make strings and borrow that method. | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings. | |||||
const char* name, const string value) { // Given char* and string | |||||
return Mnemonic(string(name), value); // make strings and borrow that method. | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings. | |||||
const string name, const char* value) { // Given string and char* | |||||
return Mnemonic(name, string(value)); // make strings and borrow that method. | |||||
} | |||||
inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c++ strings. | |||||
const string name, const string value) { // Givent string and string | |||||
ConfigurationMnemonic* N = // Create a new Mnemonic | |||||
new ConfigurationMnemonic(name, value); // using the values provided, | |||||
myMnemonics.push_back(N); // add it to my list, then | |||||
return(*this); // dereference and return myself. | |||||
} | |||||
//// Configuration Data //////////////////////////////////////////////////////// | |||||
inline char ConfigurationData::Data(int Index) { // Returns char from Data[Index] | |||||
if(0 > Index || Index >= myBufferSize) { // Check that index is in range | |||||
return 0; // and return 0 if it is not. | |||||
} // If Index is within range then | |||||
return myDataBuffer[Index]; // return the byte requested. | |||||
} | |||||
inline int ConfigurationData::Index() { // Reads the current Index. | |||||
return myIndex; | |||||
} | |||||
inline int ConfigurationData::Index(int i) { // Changes the current Index. | |||||
if(0 > i || i >= myBufferSize) { // If i is out of range then | |||||
return myIndex; // return the current Index unchanged. | |||||
} // If i is within range then | |||||
myIndex = i; // change the Index to i and | |||||
return myIndex; // return the changed Index. | |||||
} | |||||
inline int ConfigurationData::Line() { // Reads the current Line number. | |||||
return myLine; | |||||
} | |||||
inline int ConfigurationData::addNewLines(int Count) { // Increments the Line number. | |||||
myLine += Count; // Add the number of new lines. | |||||
return myLine; // Return the current Line number. | |||||
} | |||||
//// Configuration Translator ////////////////////////////////////////////////// | |||||
inline StringTranslator::StringTranslator( // Construct this with | |||||
string& Variable, // the variable to map, | |||||
string Initializer) : // and the default value. | |||||
myVariable(Variable), | |||||
myInitializer(Initializer) { | |||||
} | |||||
inline void StringTranslator::translate(const char* Value) { // Provide a translation method. | |||||
myVariable = string(Value); // String to String = simple copy. | |||||
} | |||||
inline void StringTranslator::initialize() { // Provide an initialization method. | |||||
myVariable = myInitializer; // Revert to the initializer value. | |||||
} | |||||
inline IntegerTranslator::IntegerTranslator( // Construct this with | |||||
int& Variable, // the variable to map, | |||||
int Initializer, // and the default value. | |||||
int Radix) : // For this one we also need a Radix. | |||||
myVariable(Variable), | |||||
myInitializer(Initializer), | |||||
myRadix(Radix) { | |||||
} | |||||
inline void IntegerTranslator::translate(const char* Value) { // Provide a translation method. | |||||
char* dummy; // Throw away ptr for strtol(). | |||||
myVariable = strtol(Value, &dummy, myRadix); // Convert the string w/ strtol(). | |||||
} | |||||
inline void IntegerTranslator::initialize() { // Provide an initialization method. | |||||
myVariable = myInitializer; // Revert to the initializer value. | |||||
} | |||||
inline DoubleTranslator::DoubleTranslator( // Construct this with | |||||
double& Variable, // the variable to map, | |||||
double Initializer) : // and the default value. | |||||
myVariable(Variable), | |||||
myInitializer(Initializer) { | |||||
} | |||||
inline void DoubleTranslator::translate(const char* Value) { // Provide a translation method. | |||||
char* dummy; // Throw away ptr for strtod(). | |||||
myVariable = strtod(Value, &dummy); // Convert the string w/ strtod(). | |||||
} | |||||
inline void DoubleTranslator::initialize() { // Provide an initialization method. | |||||
myVariable = myInitializer; // Revert to the initializer value. | |||||
} | |||||
inline BoolTranslator::BoolTranslator( // Construct this with | |||||
bool& Variable, // the variable to map, | |||||
bool Initializer) : // and the default value. | |||||
myVariable(Variable), | |||||
myInitializer(Initializer) { | |||||
} | |||||
inline void BoolTranslator::translate(const char* Value) { // Provide a translation method. | |||||
if( | |||||
(0 == strcmp(Value,"on")) || | |||||
(0 == strcmp(Value,"true")) || // on, true, yes, and 1 are | |||||
(0 == strcmp(Value, "yes")) || // interpreted as a boolean true. | |||||
(0 == strcmp(Value, "1")) | |||||
) { | |||||
myVariable = true; | |||||
} else { // Anything else is interpreted as | |||||
myVariable = false; // boolean false. | |||||
} | |||||
} | |||||
inline void BoolTranslator::initialize() { // Provide an initialization method. | |||||
myVariable = myInitializer; // Revert to the initializer value. | |||||
} | |||||
//// Configuration Mnemonic //////////////////////////////////////////////////// | |||||
inline ConfigurationMnemonic::ConfigurationMnemonic( // To make one, provide both parts. | |||||
string Name, string Value) : | |||||
myName(Name), | |||||
myValue(Value) { | |||||
} | |||||
inline bool ConfigurationMnemonic::test(string Name) { // Test to see if this Mnemonic matches. | |||||
return (0 == Name.compare(myName)); // Return true if Name and myName match. | |||||
} | |||||
inline string ConfigurationMnemonic::Value() { // If it does then we will need it's value. | |||||
return myValue; | |||||
} |
// faults.hpp | |||||
// | |||||
// Copyright (C) MicroNeil Research Corporation 2009 | |||||
// This file is part of the CodeDweller library. | |||||
// See www.codedweller.com for details. | |||||
// | |||||
// Faults and Checks are classes we can use in place of assert() to handle | |||||
// unreasonable or necessary conditions in our code. They are constructed with | |||||
// friendly descriptions (and optionally error codes) and then used just | |||||
// like assert() would be used-- except they are designed to remain in the | |||||
// production code. After all, assert() is a C (not C++) concept. | |||||
// | |||||
// A ...Check(test_expression) activates when the test_expression is not true. | |||||
// A ...Fault(text_expression) activates when the test_expression is true. | |||||
// | |||||
// An Abort...() sends it's description to cerr then aborts (no cleanup). | |||||
// An Exit...() sends it's description to cerr then exits with a result code. | |||||
// A Runtime...() throws a runtime_error (self) with it's description in what(). | |||||
// A Logic...() throws a logic_error (self) with it's description in what(). | |||||
#ifndef MNR_faults | |||||
#define MNR_faults | |||||
#include <stdexcept> | |||||
#include <cstdlib> | |||||
#include <iostream> | |||||
#include <string> | |||||
using namespace std; | |||||
const int DefaultExitCode = EXIT_FAILURE; // Use this when no code is provided. | |||||
class AbortCheck { // If this check is false we will abort. | |||||
private: | |||||
const string myDescription; // This is what I have to say. | |||||
public: | |||||
AbortCheck(const string& Text) : myDescription(Text) {} // I am constructed with a description | |||||
void operator()(bool X) const { // Apply me like assert(exp) | |||||
if(false == X) { // If the expression is false then we | |||||
cerr << myDescription << endl; // failed the check so we display our | |||||
abort(); // description and abort. | |||||
} | |||||
} | |||||
const string Description() { return myDescription; } // You can ask for my Description. | |||||
}; | |||||
class AbortFault { // If this fault occurs we will abort. | |||||
private: | |||||
const string myDescription; // This is what I have to say. | |||||
public: | |||||
AbortFault(const string& Text) : myDescription(Text) {} // I am constructed with a description | |||||
void operator()(bool X) const { // Apply me like assert(! exp) | |||||
if(true == X) { // If the expression is true then we | |||||
cerr << myDescription << endl; // have a fault so we display our fault | |||||
abort(); // description and abort. | |||||
} | |||||
} | |||||
const string Description() const { return myDescription; } // You can ask for my Description. | |||||
}; | |||||
class ExitCheck { // If this check is false we will exit. | |||||
private: | |||||
const string myDescription; // This is what I have to say. | |||||
const int myExitCode; // This is what I send to exit(). | |||||
public: | |||||
ExitCheck(const string& Text, int Code=DefaultExitCode) : // I am constructed with a description | |||||
myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. | |||||
void operator()(bool X) const { // Apply me like assert(exp) | |||||
if(false == X) { // If the expression is false then we | |||||
cerr << myDescription << endl; // failed the check so we display our | |||||
exit(myExitCode); // description and exit with our code. | |||||
} | |||||
} | |||||
const string Description() { return myDescription; } // You can ask for my Description. | |||||
const int ExitCode() { return myExitCode; } // You can ask for my ExitCode. | |||||
}; | |||||
class ExitFault { // If this fault occurs we will exit. | |||||
private: | |||||
const string myDescription; // This is what I have to say. | |||||
const int myExitCode; // This is what I send to exit(). | |||||
public: | |||||
ExitFault(const string& Text, int Code=DefaultExitCode) : // I am constructed with a description | |||||
myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. | |||||
void operator()(bool X) const { // Apply me like assert(! exp) | |||||
if(true == X) { // If the expression is true then we | |||||
cerr << myDescription << endl; // have a fault so we display our fault | |||||
exit(myExitCode); // description and exit with our code. | |||||
} | |||||
} | |||||
const string Description() const { return myDescription; } // You can ask for my Description. | |||||
const int ExitCode() const { return myExitCode; } // You can ask for my ExitCode. | |||||
}; | |||||
class RuntimeCheck : public runtime_error { // Throw if this check fails. | |||||
public: | |||||
RuntimeCheck(const string& Text) : runtime_error(Text) {} // Construct me with a description. | |||||
void operator()(bool X) const { // Apply me like assert(exp) | |||||
if(false == X) { // If the expression is false then we | |||||
throw *this; // failed the check so we throw. | |||||
} | |||||
} | |||||
}; | |||||
class RuntimeFault : public runtime_error { // Throw if we find this fault. | |||||
public: | |||||
RuntimeFault(const string& Text) : runtime_error(Text) {} // Construct me with a description. | |||||
void operator()(bool X) const { // Apply me like assert(exp) | |||||
if(true == X) { // If the expression is true then we | |||||
throw *this; // found the fault so we throw. | |||||
} | |||||
} | |||||
}; | |||||
class LogicCheck : public logic_error { // Throw if this check fails. | |||||
public: | |||||
LogicCheck(const string& Text) : logic_error(Text) {} // Construct me with a description. | |||||
void operator()(bool X) const { // Apply me like assert(exp) | |||||
if(false == X) { // If the expression is false then we | |||||
throw *this; // failed the check so we throw. | |||||
} | |||||
} | |||||
}; | |||||
class LogicFault : public logic_error { // Throw if we find this fault. | |||||
public: | |||||
LogicFault(const string& Text) : logic_error(Text) {} // Construct me with a description. | |||||
void operator()(bool X) const { // Apply me like assert(exp) | |||||
if(true == X) { // If the expression is true then we | |||||
throw *this; // found the fault so we throw. | |||||
} | |||||
} | |||||
}; | |||||
#endif | |||||
// End Of Include MNR_faults Once Only ========================================= |
// histogram.hpp | |||||
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation | |||||
// Class to capture a histogram of events using a <set> | |||||
#ifndef mn_histogram_included | |||||
#define mn_histogram_included | |||||
#include <set> | |||||
using namespace std; | |||||
/** The Histogram class is managed set of HistogramRecords. | |||||
*** We play some naughty tricks with pointers to break the rules and | |||||
*** directly manipulate the counts of HistogramRecords stored in the | |||||
*** set - thus saving space, complexity, and cycles. The set allows us | |||||
*** to add new records as needed and locate existing records quickly. | |||||
*** At any point in time, the set contains all of the event (hit) counts | |||||
*** ordered by key. | |||||
**/ | |||||
class HistogramRecord { // A record to assocate a key and count. | |||||
public: | |||||
int Key; // Here is the key. | |||||
int Count; // Here is the count. | |||||
HistogramRecord(const int NewKey) : // We must have a key to make one. | |||||
Key(NewKey), Count(0) {} // and a new one starts at count 0. | |||||
bool operator<(const HistogramRecord& Right) const { // To live in a set we need to < | |||||
return (Key < Right.Key); // properly based on the key. | |||||
} | |||||
}; | |||||
class Histogram : public set<HistogramRecord> { // A Histogram is a set of HistogramRecords | |||||
private: // and a private hit counter... | |||||
int HitCount; | |||||
public: | |||||
Histogram() : HitCount(0) {} | |||||
// with a few extra public functions. The | |||||
int hit(const int EventKey, const int Adjustment = 1) { // hit() method increments a specific count. | |||||
HistogramRecord E(EventKey); // First, make a record for the event key. | |||||
insert(E); // Insert the new record (if it's not there). | |||||
set<HistogramRecord>::iterator iE = // Find either the pre-existing or the new | |||||
find(E); // record for this key. | |||||
int* C; // Play naughty pointer games to access | |||||
C = const_cast<int*>(&((*iE).Count)); // the Count for this record inside the | |||||
(*C) += Adjustment; // set and add our Adjustment to it. | |||||
HitCount += Adjustment; // Accumulate the adjustments overall. | |||||
return(*C); // Return the count for this key. | |||||
} | |||||
int Hits() { return HitCount; } // Return the sum of hits so far. | |||||
void reset() { // Reset the histogram to zero. | |||||
HitCount = 0; // That means no counts, and | |||||
clear(); // an empty set of records. | |||||
} | |||||
}; | |||||
#endif | |||||
// MANGLER.CPP | |||||
// | |||||
// (C) 1984-2009 MicroNeil Research Corporation | |||||
// Derived from Version 1 of Mangler Encryption Algorythm, 1984. | |||||
// Derived from Version 2 of Mangler Encryption Algorythm, 1998. | |||||
// | |||||
// 20021008 _M | |||||
// Found and corrected range bug in ChaosDriver(void) where | |||||
// ~Position might access a location outside the fill. Replaced | |||||
// ~Position with Position^0xff which has the intended effect. | |||||
// 20020119 _M Version 3.0 | |||||
// | |||||
// Mangler encryption engine object. | |||||
// Using new optimized chaos driver for uniformity experiments. | |||||
// Important in this experiment is proof of highest possible entropy. | |||||
#include "mangler.hpp" | |||||
unsigned char MANGLER::ChaosDriver(void) { // Return the current | |||||
return Fill[Fill[Position]^Fill[Position^0xff]]; // chaos engine output | |||||
} // value. | |||||
// As of version 3 the output of the chaos driver was strengthened for | |||||
// cryptography and to increase the sensitivity of the output for use | |||||
// as a random number generator. In version 2, the software would simply | |||||
// return the fill value at the engine's current position. In the new | |||||
// version two distinct fill values are involved in abstracting the | |||||
// value of Position and determining the final output value and the Position | |||||
// value itself is used to add complexity to the output. | |||||
unsigned char MANGLER::Rotate(unsigned char i) { // Bitwise rotates i | |||||
return ( | |||||
(i & 0x80)? // This operation is | |||||
(i<<1)+1: // described without | |||||
(i<<1) // using asm. | |||||
); | |||||
} | |||||
void MANGLER::ChaosDriver(unsigned char i) { // Drives chaos engine. | |||||
// First we move our mixing position in the fill buffer forward. | |||||
Position=( // Move mixing position. | |||||
Position+1+ // Move at least 1, then | |||||
(Fill[Position]&0x0f) // maybe a few more. | |||||
)%256; // But stay within the fill. | |||||
// The fill position in version 2 was simply incremented. This allowed | |||||
// for an attacker to predict something important about the state of | |||||
// the chaos engine. The new method above uses abstraction through the | |||||
// fill buffer to introduce "jitter" when setting a new position based | |||||
// on data that is hidden from the outside. | |||||
// Next we abstract the incoming character through the fill buffer and | |||||
// use it to select fill data to rotate and swap. | |||||
unsigned char Swap = ((Fill[Position]^Fill[i])+Position+i)%256; | |||||
unsigned char Tmp; | |||||
Tmp = Fill[Swap]; | |||||
Fill[Swap]=Fill[Position]; | |||||
Fill[Position]=Rotate(Tmp); | |||||
// Whenever the Swap and Path positions are the same, the result is | |||||
// that no data is swapped in the chaos field. We resolve that by | |||||
// recalling the ChaosDriver. This has the added effect of increasing | |||||
// the complexity and making it more difficult to predict the state | |||||
// of the engine... particularly because the engine evloves to a new | |||||
// state under these conditions without having exposed that change | |||||
// to the outside world. | |||||
if(Position==Swap) ChaosDriver(Tmp); // If we didn't swap, recurse. | |||||
} | |||||
// The encryption / decryption scheme works by modulating an input data | |||||
// stream with a chaotic system and allowing the encrypted stream to drive | |||||
// the chaotic system of both the transmitter and receiver. This will | |||||
// synchronize the two chaotic systems and allow the receiving system to | |||||
// "predict" the state of the transmiting system so that it can properly | |||||
// demodulate the encrypted stream. Both chaotic systems must start in the | |||||
// same state with the same fill data characteristics or else the two | |||||
// chaotic systems evolve to further divergent states. | |||||
unsigned char MANGLER::Encrypt(unsigned char i) { | |||||
unsigned char g = ChaosDriver() ^ i; // Take the output of the | |||||
ChaosDriver(g); // chaos engine and use it | |||||
return g; // to moduleate the input. | |||||
} // Then drive the engine | |||||
// with the encrypted data. | |||||
unsigned char MANGLER::Decrypt(unsigned char i) { | |||||
unsigned char g = ChaosDriver() ^ i; // Take the output of the | |||||
ChaosDriver(i); // chaos engine and use it | |||||
return g; // to demodulate the input. | |||||
} // then drive the engine | |||||
// with the original input. | |||||
MANGLER::MANGLER(void) : Position(0) { // The default constructor sets | |||||
for(unsigned int c = 0;c<256;c++) // the key to the root primary | |||||
Fill[c]=(unsigned char) c; // value and Position to 0. | |||||
} | |||||
// MANGLER.HPP | |||||
// | |||||
// (C) 1984-2009 MicroNeil Research Corporation | |||||
// Derived from Version 1 of Mangler Encryption Algorythm, 1984. | |||||
// Derived from Version 2 of Mangler Encryption Algorythm, 1998. | |||||
// | |||||
// 20020119 _M Mangler V3. | |||||
// Mangler object header file. | |||||
// If it's already been included, it doesn't need to be included again. | |||||
#ifndef _MANGLER_ | |||||
#define _MANGLER_ | |||||
class MANGLER { | |||||
private: | |||||
unsigned char Fill[256]; // Where to store the fill. | |||||
unsigned int Position; // Where to put position. | |||||
unsigned char Rotate(unsigned char); // Bitwise Rotate Utility. | |||||
unsigned char ChaosDriver(void); // Returns current chaos. | |||||
void ChaosDriver(unsigned char i); // Drives chaos forward. | |||||
public: | |||||
unsigned char Encrypt(unsigned char i); // Returns encrypted data. | |||||
unsigned char Decrypt(unsigned char i); // Returns decrypted data. | |||||
MANGLER(void); // Default. | |||||
}; | |||||
#endif | |||||
// networking.cpp | |||||
// Copyright (C) 2006-2009 MicroNeil Research Corporation. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
//============================================================================== | |||||
// See networking.hpp for notes. | |||||
// See networking.inline.hpp for inlined methods & functions. | |||||
#include "networking.hpp" | |||||
Networking Network; // Finally creating the Network instance. | |||||
//// Platform Specific Stuff /////////////////////////////////////////////////// | |||||
#if defined(WIN32) || defined(WIN64) | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//// Being Windows specific code | |||||
WSADATA WSSTartData; // Socket library data structure. | |||||
// Error description handling for humans. | |||||
string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno. | |||||
string s = ""; // Message string. | |||||
switch(Errno) { // Assign the appropriate message. | |||||
case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break; | |||||
case WSA_NOT_ENOUGH_MEMORY: s = "WSA_NOT_ENOUGH_MEMORY"; break; | |||||
case WSA_INVALID_PARAMETER: s = "WSA_INVALID_PARAMETER"; break; | |||||
case WSA_OPERATION_ABORTED: s = "WSA_OPERATION_ABORTED"; break; | |||||
case WSA_IO_INCOMPLETE: s = "WSA_IO_INCOMPLETE"; break; | |||||
case WSA_IO_PENDING: s = "WSA_IO_PENDING"; break; | |||||
case WSAEINTR: s = "WSAEINTR"; break; | |||||
case WSAEBADF: s = "WSAEBADF"; break; | |||||
case WSAEACCES: s = "WSAEACCES"; break; | |||||
case WSAEFAULT: s = "WSAEFAULT"; break; | |||||
case WSAEINVAL: s = "WSAEINVAL"; break; | |||||
case WSAEMFILE: s = "WSAEMFILE"; break; | |||||
case WSAEWOULDBLOCK: s = "WSAEWOULDBLOCK"; break; | |||||
case WSAEINPROGRESS: s = "WSAEINPROGRESS"; break; | |||||
case WSAEALREADY: s = "WSAEALREADY"; break; | |||||
case WSAENOTSOCK: s = "WSAENOTSOCK"; break; | |||||
case WSAEDESTADDRREQ: s = "WSAEDESTADDRREQ"; break; | |||||
case WSAEMSGSIZE: s = "WSAEMSGSIZE"; break; | |||||
case WSAEPROTOTYPE: s = "WSAEPROTOTYPE"; break; | |||||
case WSAENOPROTOOPT: s = "WSAENOPROTOOPT"; break; | |||||
case WSAEPROTONOSUPPORT: s = "WSAEPROTONOSUPPORT"; break; | |||||
case WSAESOCKTNOSUPPORT: s = "WSAESOCKTNOSUPPORT"; break; | |||||
case WSAEOPNOTSUPP: s = "WSAEOPNOTSUPP"; break; | |||||
case WSAEPFNOSUPPORT: s = "WSAEPFNOSUPPORT"; break; | |||||
case WSAEAFNOSUPPORT: s = "WSAEAFNOSUPPORT"; break; | |||||
case WSAEADDRINUSE: s = "WSAEADDRINUSE"; break; | |||||
case WSAEADDRNOTAVAIL: s = "WSAEADDRNOTAVAIL"; break; | |||||
case WSAENETDOWN: s = "WSAENETDOWN"; break; | |||||
case WSAENETUNREACH: s = "WSAENETUNREACH"; break; | |||||
case WSAENETRESET: s = "WSAENETRESET"; break; | |||||
case WSAECONNABORTED: s = "WSAECONNABORTED"; break; | |||||
case WSAECONNRESET: s = "WSAECONNRESET"; break; | |||||
case WSAENOBUFS: s = "WSAENOBUFS"; break; | |||||
case WSAEISCONN: s = "WSAEISCONN"; break; | |||||
case WSAENOTCONN: s = "WSAENOTCONN"; break; | |||||
case WSAESHUTDOWN: s = "WSAESHUTDOWN"; break; | |||||
case WSAETOOMANYREFS: s = "WSAETOOMANYREFS"; break; | |||||
case WSAETIMEDOUT: s = "WSAETIMEDOUT"; break; | |||||
case WSAECONNREFUSED: s = "WSAECONNREFUSED"; break; | |||||
case WSAELOOP: s = "WSAELOOP"; break; | |||||
case WSAENAMETOOLONG: s = "WSAENAMETOOLONG"; break; | |||||
case WSAEHOSTDOWN: s = "WSAEHOSTDOWN"; break; | |||||
case WSAEHOSTUNREACH: s = "WSAEHOSTUNREACH"; break; | |||||
case WSAENOTEMPTY: s = "WSAENOTEMPTY"; break; | |||||
case WSAEPROCLIM: s = "WSAEPROCLIM"; break; | |||||
case WSAEUSERS: s = "WSAEUSERS"; break; | |||||
case WSAEDQUOT: s = "WSAEDQUOT"; break; | |||||
case WSAESTALE: s = "WSAESTALE"; break; | |||||
case WSAEREMOTE: s = "WSAEREMOTE"; break; | |||||
case WSASYSNOTREADY: s = "WSASYSNOTREADY"; break; | |||||
case WSAVERNOTSUPPORTED: s = "WSAVERNOTSUPPORTED"; break; | |||||
case WSANOTINITIALISED: s = "WSANOTINITIALISED"; break; | |||||
case WSAEDISCON: s = "WSAEDISCON"; break; | |||||
case WSAENOMORE: s = "WSAENOMORE"; break; | |||||
case WSAECANCELLED: s = "WSAECANCELLED"; break; | |||||
case WSAEINVALIDPROCTABLE: s = "WSAEINVALIDPROCTABLE"; break; | |||||
case WSAEINVALIDPROVIDER: s = "WSAEINVALIDPROVIDER"; break; | |||||
case WSAEPROVIDERFAILEDINIT: s = "WSAEPROVIDERFAILEDINIT"; break; | |||||
case WSASYSCALLFAILURE: s = "WSASYSCALLFAILURE"; break; | |||||
case WSASERVICE_NOT_FOUND: s = "WSASERVICE_NOT_FOUND"; break; | |||||
case WSATYPE_NOT_FOUND: s = "WSATYPE_NOT_FOUND"; break; | |||||
case WSA_E_NO_MORE: s = "WSA_E_NO_MORE"; break; | |||||
case WSA_E_CANCELLED: s = "WSA_E_CANCELLED"; break; | |||||
case WSAEREFUSED: s = "WSAEREFUSED"; break; | |||||
case WSAHOST_NOT_FOUND: s = "WSAHOST_NOT_FOUND"; break; | |||||
case WSATRY_AGAIN: s = "WSATRY_AGAIN"; break; | |||||
case WSANO_RECOVERY: s = "WSANO_RECOVERY"; break; | |||||
case WSANO_DATA: s = "WSANO_DATA"; break; | |||||
case WSA_QOS_RECEIVERS: s = "WSA_QOS_RECEIVERS"; break; | |||||
case WSA_QOS_SENDERS: s = "WSA_QOS_SENDERS"; break; | |||||
case WSA_QOS_NO_SENDERS: s = "WSA_QOS_NO_SENDERS"; break; | |||||
case WSA_QOS_NO_RECEIVERS: s = "WSA_QOS_NO_RECEIVERS"; break; | |||||
case WSA_QOS_REQUEST_CONFIRMED: s = "WSA_QOS_REQUEST_CONFIRMED"; break; | |||||
case WSA_QOS_ADMISSION_FAILURE: s = "WSA_QOS_ADMISSION_FAILURE"; break; | |||||
case WSA_QOS_POLICY_FAILURE: s = "WSA_QOS_POLICY_FAILURE"; break; | |||||
case WSA_QOS_BAD_STYLE: s = "WSA_QOS_BAD_STYLE"; break; | |||||
case WSA_QOS_BAD_OBJECT: s = "WSA_QOS_BAD_OBJECT"; break; | |||||
case WSA_QOS_TRAFFIC_CTRL_ERROR: s = "WSA_QOS_TRAFFIC_CTRL_ERROR"; break; | |||||
case WSA_QOS_GENERIC_ERROR: s = "WSA_QOS_GENERIC_ERROR"; break; | |||||
case WSA_QOS_ESERVICETYPE: s = "WSA_QOS_ESERVICETYPE"; break; | |||||
case WSA_QOS_EFLOWSPEC: s = "WSA_QOS_EFLOWSPEC"; break; | |||||
case WSA_QOS_EPROVSPECBUF: s = "WSA_QOS_EPROVSPECBUF"; break; | |||||
case WSA_QOS_EFILTERSTYLE: s = "WSA_QOS_EFILTERSTYLE"; break; | |||||
case WSA_QOS_EFILTERTYPE: s = "WSA_QOS_EFILTERTYPE"; break; | |||||
case WSA_QOS_EFILTERCOUNT: s = "WSA_QOS_EFILTERCOUNT"; break; | |||||
case WSA_QOS_EOBJLENGTH: s = "WSA_QOS_EOBJLENGTH"; break; | |||||
case WSA_QOS_EFLOWCOUNT: s = "WSA_QOS_EFLOWCOUNT"; break; | |||||
case WSA_QOS_EPOLICYOBJ: s = "WSA_QOS_EPOLICYOBJ"; break; | |||||
case WSA_QOS_EFLOWDESC: s = "WSA_QOS_EFLOWDESC"; break; | |||||
case WSA_QOS_EPSFLOWSPEC: s = "WSA_QOS_EPSFLOWSPEC"; break; | |||||
case WSA_QOS_EPSFILTERSPEC: s = "WSA_QOS_EPSFILTERSPEC"; break; | |||||
case WSA_QOS_ESDMODEOBJ: s = "WSA_QOS_ESDMODEOBJ"; break; | |||||
case WSA_QOS_ESHAPERATEOBJ: s = "WSA_QOS_ESHAPERATEOBJ"; break; | |||||
case WSA_QOS_RESERVED_PETYPE: s = "WSA_QOS_RESERVED_PETYPE"; break; | |||||
#ifdef WSA_QOS_EUNKOWNPSOBJ | |||||
case WSA_QOS_EUNKOWNPSOBJ: s = "WSA_QOS_EUNKOWNPSOBJ"; break; | |||||
#endif | |||||
} | |||||
Msg.append(" "); // Add a space to the existing message. | |||||
if(0 < s.length()) { // If we know the message for Errno | |||||
Msg.append(s); // then append it. | |||||
} | |||||
else { // If we don't know what Errno means | |||||
ostringstream ErrNoMsg; // then say so and pass on Errno as | |||||
ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno; // well so someone can figure it out. | |||||
Msg.append(ErrNoMsg.str()); | |||||
} | |||||
return Msg; | |||||
}; | |||||
// Networking Constructor ////////////////////////////////////////////////////// | |||||
// Handles any necessary setup of Network Module resources. | |||||
Networking::Networking() { // Upon initialization, | |||||
if(0 != WSAStartup(MAKEWORD (2,0), &WSSTartData)) { // startup the Winsock2.0 DLL. | |||||
throw InitializationError( // If that fails then throw! | |||||
"Networking::Networking() if(0 != WSAStartup(MAKEWORD (2,0), &WSSTartData))" | |||||
); | |||||
} | |||||
} | |||||
// Networking Destructor /////////////////////////////////////////////////////// | |||||
// Handles any necessary cleanup of Network Module resources. | |||||
Networking::~Networking() { // Upon shutdown, | |||||
WSACleanup(); // shutdown the Winsock DLL. | |||||
} | |||||
//// Emd Windows specific code | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
#else | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//// Begin GNU specific code | |||||
// Error description handling for humans. | |||||
string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno. | |||||
Msg.append(" "); Msg.append(strerror(Errno)); | |||||
return Msg; | |||||
}; | |||||
// Networking Constructor ////////////////////////////////////////////////////// | |||||
// Handles any necessary setup of Network Module resources. | |||||
Networking::Networking() { // Upon initialization, | |||||
// Nothing So Far... // nothing special required. | |||||
} | |||||
// Networking Destructor /////////////////////////////////////////////////////// | |||||
// Handles any necessary cleanup of Network Module resources. | |||||
Networking::~Networking() { // GNU sockets cleanup, | |||||
// Nothing So Far... // nothing specail to required. | |||||
} | |||||
//// End GNU specific code | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
#endif | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//// Platform Agnostic Stuff | |||||
//// Useful Internal Bits & Pieces ///////////////////////////////////////////// | |||||
const int LowestOctetMask = 0x000000FF; // The bits to look at. | |||||
const int OneOctetInBits = 8; // The bits to shift. | |||||
void splitIP( // Split an IP into octets. | |||||
unsigned long A, // The address in host format. | |||||
int& a0, // Reference to the first octet. | |||||
int& a1, // Reference to the second octet. | |||||
int& a2, // Reference to the third octet. | |||||
int& a3 // Reference to the forth octet. | |||||
){ | |||||
a3 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the lowest order octet & move. | |||||
a2 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the next lowest octet & move. | |||||
a1 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the next lowest octet & move. | |||||
a0 = A & LowestOctetMask; // Get the highest octet. That's IT! | |||||
} | |||||
//// IP4Address methods //////////////////////////////////////////////////////// | |||||
IP4Address::operator unsigned long int() const { // Assign to unsigned long int. | |||||
return IP; // Return it. | |||||
} | |||||
IP4Address::operator string() const { // Assign to a string. | |||||
char stringbfr[IPStringBufferSize]; // Grab a temporary buffer. | |||||
memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space. | |||||
int a0, a1, a2, a3; // Grab some integers. | |||||
splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address. | |||||
sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets. | |||||
return string(stringbfr); // Return a string. | |||||
} | |||||
//// SocketAddress methods ///////////////////////////////////////////////////// | |||||
// getAddress(str, len) | |||||
const char* SocketAddress::getAddress(char* str) { // Get the IP address into a cstring. | |||||
if(NULL == str) { // If the caller did not provide a | |||||
str = IPStringBuffer; // buffer to use then we will use ours. | |||||
} | |||||
int a0, a1, a2, a3; // Grab a bunch of handy integers. | |||||
getAddress(a0, a1, a2, a3); // Get the address as octets. | |||||
sprintf(str, "%d.%d.%d.%d", a0, a1, a2, a3); // Format as dotted decimal notation. | |||||
return str; // Return the output buffer. | |||||
} | |||||
// getAddress(int& a0, int& a1, int& a2, int& a3) | |||||
void SocketAddress::getAddress(int& a0, int& a1, int& a2, int& a3) { // Get the IP address into 4 ints | |||||
unsigned long A = getAddress(); // Get the address. | |||||
splitIP(A, a0, a1, a2, a3); // Split it into octets. | |||||
} | |||||
//// TCPListener methods /////////////////////////////////////////////////////// | |||||
TCPListener::TCPListener(unsigned short Port) { // Set up localhost on this Port. | |||||
LocalAddress.setPort(Port); // Establish the port. | |||||
LocalAddress.setAddress(LOCALHOST); // Set the address to LOCALHOST. | |||||
MaxPending = DefaultMaxPending; // Use the default inbound queue size. | |||||
ReuseAddress = true; // ReuseAddress on by default. | |||||
OpenStage1Complete = false; // This stage of open() not yet done. | |||||
OpenStage2Complete = false; // This stage of open() not yet done. | |||||
// Create a socket... | |||||
LastError = 0; | |||||
Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket. | |||||
if(INVALID_SOCKET == Handle) { // If that operation failed then | |||||
LastError = Network.getLastError(); // grab the error code and | |||||
throw Networking::SocketCreationError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPListener::TCPListener().socket()", LastError)); | |||||
} | |||||
} | |||||
TCPListener::TCPListener(SocketAddress& WhereToBind) { // Set up specific "name" for listening. | |||||
LocalAddress = WhereToBind; // Make my Local address as provided. | |||||
MaxPending = DefaultMaxPending; // Use the default inbound queue size. | |||||
ReuseAddress = true; // ReuseAddress on by default. | |||||
OpenStage1Complete = false; // This stage of open() not yet done. | |||||
OpenStage2Complete = false; // This stage of open() not yet done. | |||||
// Create a socket... | |||||
LastError = 0; | |||||
Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket. | |||||
if(INVALID_SOCKET == Handle) { // If that operation failed then | |||||
LastError = Network.getLastError(); // grab the error code and | |||||
throw Networking::SocketCreationError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPListener::TCPListener().socket()", LastError)); | |||||
} | |||||
} | |||||
// open() | |||||
void TCPListener::open() { // Open when ready. | |||||
if(OpenSucceeded) return; // If open already, we're done. | |||||
LastError = 0; // Clear the last error. | |||||
bool SuccessFlag = true; // Start optimistically. | |||||
// Set SO_REUSEADDR if turned on | |||||
if(!OpenStage1Complete) { // Do this stage only once. | |||||
int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. | |||||
int result = // Set SO_REUSEADDR before bind(). | |||||
setsockopt( | |||||
Handle, | |||||
SOL_SOCKET, | |||||
SO_REUSEADDR, | |||||
(char*) &ReuseAddress_Flag, | |||||
sizeof(ReuseAddress_Flag)); | |||||
if(0 > result) { // If there was an error then | |||||
SuccessFlag = false; // we did not succeed. | |||||
LastError = Network.getLastError(); // Capture the error information and | |||||
throw Networking::SocketSetSockOptError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPListener::open().setsockopt(SO_REUSEADDR)", LastError)); | |||||
} | |||||
OpenStage1Complete = true; // Stage 1 complete now. | |||||
} // End of open() stage 1 | |||||
// Next we bind it... | |||||
if(!OpenStage2Complete) { // Do this stage only once. | |||||
int result = // Bind our socket to the LocalAddress. | |||||
bind( | |||||
Handle, | |||||
LocalAddress.getPtr_sockaddr(), | |||||
LocalAddress.getAddressSize()); | |||||
if(0 > result) { // If there was an error then | |||||
SuccessFlag = false; // we did not succeed. | |||||
LastError = Network.getLastError(); // Capture the error information and | |||||
throw Networking::SocketBindError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPListener::open().bind()", LastError)); | |||||
} | |||||
OpenStage2Complete = true; // Stage 2 complete now. | |||||
} // End of open() stage 2 | |||||
// Then we put it in a listening state... | |||||
int result = listen(Handle, MaxPending); // Listen for up to MaxPending at once. | |||||
if(0 > result) { // If an error occurred then | |||||
SuccessFlag = false; // we did not succeed. | |||||
LastError = Network.getLastError(); // Capture the error information and | |||||
throw Networking::SocketListenError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPListener::open().listen()", LastError)); | |||||
} | |||||
OpenSucceeded = SuccessFlag; // So, did we succeed? | |||||
} | |||||
// acceptClient() | |||||
TCPClient* TCPListener::acceptClient() { // Accept a client connection. | |||||
LastError = 0; // Clear the last error. | |||||
socklen_t rsize = RemoteAddress.getAddressSize(); // Size as an int for accept(). | |||||
hSocket NewHandle = // Accept a new connection if available. | |||||
accept( | |||||
Handle, // use our handle, of course,... | |||||
RemoteAddress.getPtr_sockaddr(), // and store the remote hosts | |||||
&rsize); // address for us. | |||||
if(INVALID_SOCKET == NewHandle) { // If there was an error then | |||||
LastError = Network.getLastError(); // capture the error value. | |||||
if(!Network.WouldBlock(LastError)) { // If it's not a EWOULDBLOCK error | |||||
throw Networking::SocketAcceptError( // then we need to throw. | |||||
Network.DescriptiveError( | |||||
"TCPListener::acceptClient().accept()", LastError)); | |||||
} else { // EWOULDBLOCK errors are normal in | |||||
return NULL; // non blocking mode so we return | |||||
} // NULL when we see them. | |||||
} | |||||
// Set SO_NOSIGPIPE if needed | |||||
if( // On some systems we may have to | |||||
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | |||||
) { | |||||
int TurnedOn = 1; // Prepare to turn this option on. | |||||
int result = // Set SO_NOSIGPIPE. | |||||
setsockopt( | |||||
NewHandle, | |||||
SOL_SOCKET, | |||||
SO_NOSIGPIPE, | |||||
(char*) &TurnedOn, | |||||
sizeof(TurnedOn)); | |||||
if(0 > result) { // If there was an error then | |||||
LastError = Network.getLastError(); // Capture the error information | |||||
Network.closeSocket(NewHandle); // close the handle (avoid leaks) | |||||
throw Networking::SocketSetSockOptError( // and throw a descriptive exception. | |||||
Network.DescriptiveError( | |||||
"TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
} | |||||
} | |||||
// If things have gone well we can do what we came for. | |||||
return new TCPClient(*this, NewHandle, RemoteAddress); // Create the new TCPClient object. | |||||
} | |||||
//// TCPClient methods ///////////////////////////////////////////////////////// | |||||
int TCPClient::transmit(const char* bfr, int size) { // How to send a buffer of data. | |||||
if(0 == size) return 0; // Nothing to send, send nothing. | |||||
if(0 == bfr) // Watch out for null buffers. | |||||
throw Networking::SocketWriteError("TCPClient::transmit() NULL Bfr!"); | |||||
if(0 > size) // Watch out for bad sizes. | |||||
throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!"); | |||||
LastError = 0; // No errors yet. | |||||
int ByteCount = 0; // No bytes sent yet this pass. | |||||
ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. | |||||
LastError = Network.getLastError(); // Grab any error code. | |||||
bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred. | |||||
const int NoBytesSent = 0; // This is our "Would Block" result. | |||||
if(AnErrorOccurred) { // If there was an error check it out. | |||||
if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then | |||||
return NoBytesSent; // return no bytes sent (try again). | |||||
} else { // If this was a different kind of error | |||||
throw Networking::SocketWriteError( // then throw! | |||||
Network.DescriptiveError( | |||||
"TCPClient::transmit().send()", LastError)); | |||||
} | |||||
} | |||||
return ByteCount; // Usually: return the sent byte count. | |||||
} | |||||
int TCPClient::receive(char* bfr, int size) { // How to receive a buffer of data. | |||||
if(ReadBufferIsEmpty()) { // If the read buffer is empty then | |||||
fillReadBuffer(); // fill it first. | |||||
} // Optimize our transfer to the smaller | |||||
if(DataLength < size) { // of what we have or the size of the | |||||
size = DataLength; // provided buffer. This way we ony check | |||||
} // one value in our copy loop ;-) | |||||
int RemainingDataLength = size; // Capture the length of data to xfer. | |||||
while(0 < RemainingDataLength) { // While we have work to do | |||||
*bfr = *ReadPointer; // copy each byte from our ReadBuffer, | |||||
bfr++; ReadPointer++; // move the pointers to the next byte, | |||||
DataLength--; // update our ReadBuffers's DataLength, | |||||
RemainingDataLength--; // and count down the bytes left to xfer. | |||||
} | |||||
return size; // When done, say how much we moved. | |||||
} | |||||
int TCPClient::delimited_receive(char* bfr, int size, char delimiter) { // How to receive delimited data. | |||||
if(ReadBufferIsEmpty()) { // If the read buffer is empty then | |||||
fillReadBuffer(); // fill it first. | |||||
} // Optimize our transfer to the smaller | |||||
if(DataLength < size) { // of what we have or the size of the | |||||
size = DataLength; // provided buffer. This way we ony check | |||||
} // one value in our copy loop ;-) | |||||
int Count = 0; // Keep our byte count in scope. | |||||
bool DelimiterNotReached = true; // Watching for our deliimiter. | |||||
while((Count < size) && DelimiterNotReached) { // While there is work to do... | |||||
*bfr = *ReadPointer; // copy each byte from our ReadBuffer, | |||||
DelimiterNotReached = (delimiter != (*bfr)); // check for the delimiter character, | |||||
bfr++; ReadPointer++; // move the pointers to the next byte, | |||||
DataLength--; // update our ReadBuffers's DataLength, | |||||
Count++; // and count up the bytes we have moved. | |||||
} | |||||
return Count; // When done, say how much we moved. | |||||
} | |||||
//// TCPHost methods /////////////////////////////////////////////////////////// | |||||
// Constructors... | |||||
TCPHost::TCPHost(unsigned short Port) { // Will connect to localhost on Port. | |||||
RemoteAddress.setPort(Port); // Connect to Port on | |||||
RemoteAddress.setAddress(LOCALHOST); // Localhost. | |||||
ReadPointer = ReadBuffer; // Set the read position to zero. | |||||
DataLength = 0; // There is no data yet. | |||||
ReuseAddress = false; // ReuseAddress off by default. | |||||
OpenStage1Complete = false; // Stage 1 of open() not done yet. | |||||
// Create a socket to use. | |||||
LastError = 0; // Clear our last error value. | |||||
Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket. | |||||
if(0 > Handle) { // If that operation failed then | |||||
LastError = Network.getLastError(); // grab the error code and | |||||
throw Networking::SocketCreationError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPHost::TCPHost().socket()", LastError)); | |||||
} | |||||
} | |||||
TCPHost::TCPHost(SocketAddress& Remote) { // Will connect to Remote address/port. | |||||
RemoteAddress = Remote; // Capture the provided address. | |||||
ReadPointer = ReadBuffer; // Set the read position to zero. | |||||
DataLength = 0; // There is no data yet. | |||||
ReuseAddress = false; // ReuseAddress off by default. | |||||
OpenStage1Complete = false; // Stage 1 of open() not done yet. | |||||
// Create a socket to use. | |||||
LastError = 0; // Clear our last error value. | |||||
Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket. | |||||
if(0 > Handle) { // If that operation failed then | |||||
LastError = Network.getLastError(); // grab the error code and | |||||
throw Networking::SocketCreationError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPHost::TCPHost().socket()", LastError)); | |||||
} | |||||
} | |||||
// Methods... | |||||
void TCPHost::open() { // We provide open(). | |||||
if(OpenSucceeded) return; // If open already, we're done. | |||||
LastError = 0; // Clear our LastError value. | |||||
bool SuccessFlag = true; // Begin optimistically. | |||||
// Set Socket Options | |||||
if(!OpenStage1Complete) { // If we haven't done this yet: | |||||
// Set SO_REUSEADDR if turned on | |||||
int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. | |||||
int result = // Set SO_REUSEADDR before bind(). | |||||
setsockopt( | |||||
Handle, | |||||
SOL_SOCKET, | |||||
SO_REUSEADDR, | |||||
(char*) &ReuseAddress_Flag, | |||||
sizeof(ReuseAddress_Flag)); | |||||
if(0 > result) { // If there was an error then | |||||
SuccessFlag = false; // we did not succeed. | |||||
LastError = Network.getLastError(); // Capture the error information and | |||||
throw Networking::SocketSetSockOptError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPHost::open().setsockopt(SO_REUSEADDR)", LastError)); | |||||
} | |||||
// Set SO_NOSIGPIPE if needed | |||||
if( // On some systems we may have to | |||||
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | |||||
) { | |||||
int TurnedOn = 1; // Prepare to turn this option on. | |||||
int result = // Set SO_NOSIGPIPE. | |||||
setsockopt( | |||||
Handle, | |||||
SOL_SOCKET, | |||||
SO_NOSIGPIPE, | |||||
(char*) &TurnedOn, | |||||
sizeof(TurnedOn)); | |||||
if(0 > result) { // If there was an error then | |||||
SuccessFlag = false; // we did not succeed. | |||||
LastError = Network.getLastError(); // Capture the error information and | |||||
throw Networking::SocketSetSockOptError( // throw. | |||||
Network.DescriptiveError( | |||||
"TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
} | |||||
} | |||||
OpenStage1Complete = true; // Skip this section from now on. | |||||
} // Done with stage 1. | |||||
// Connect the socekt to the Host. | |||||
int result = // Connect to the remote host | |||||
connect( // using the socket we just | |||||
Handle, // stored in Handle and | |||||
RemoteAddress.getPtr_sockaddr(), // the Remote address. | |||||
RemoteAddress.getAddressSize()); | |||||
if(0 > result) { // If there was an error then | |||||
SuccessFlag = false; // we did not succeed. | |||||
LastError = Network.getLastError(); // Record the error data. | |||||
if(Network.IsConnected(LastError)) { // If we actually did succeed then | |||||
SuccessFlag = true; // say so. (Silly Winsock!) | |||||
} else // But if that's not the case check | |||||
if( // to see if something bad happened - | |||||
!Network.WouldBlock(LastError) && // not just would-block, or | |||||
!Network.InProgress(LastError) // in progress... | |||||
) { // If it was something other than | |||||
throw Networking::SocketConnectError( // WouldBlock or InProgress then | |||||
Network.DescriptiveError( // throw! | |||||
"TCPHost::open().connect()", LastError)); | |||||
} // If it was WouldBlock then it's | |||||
} // considered to be ok. | |||||
OpenSucceeded = SuccessFlag; // So, are we open now? | |||||
} | |||||
int TCPHost::transmit(const char* bfr, int size) { // How to send a buffer of data. | |||||
LastError = 0; // No errors yet. | |||||
if(0 == size) return 0; // Nothing to send, send nothing. | |||||
if(0 == bfr) // Watch out for null buffers. | |||||
throw Networking::SocketWriteError("TCPHost::transmit() NULL Bfr!"); | |||||
if(0 > size) // Watch out for bad sizes. | |||||
throw Networking::SocketWriteError("TCPHost::transmit() 0 > size!"); | |||||
int ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. | |||||
if(0 > ByteCount) ByteCount = 0; // Mask error results as 0 bytes sent. | |||||
if(size > ByteCount) { // If we didn't send it all check it out. | |||||
LastError = Network.getLastError(); // Grab the error code. | |||||
if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
return ByteCount; // it was a partial snd - return. | |||||
} else { // If this was a different kind of error | |||||
throw Networking::SocketWriteError( // then throw! | |||||
Network.DescriptiveError( | |||||
"TCPHost::transmit().send()", LastError)); | |||||
} | |||||
} | |||||
return ByteCount; // Ultimately return the byte count. | |||||
} | |||||
int TCPHost::receive(char* bfr, int size) { // How to receive a buffer of data. | |||||
if(ReadBufferIsEmpty()) { // If the read buffer is empty then | |||||
fillReadBuffer(); // fill it first. | |||||
} // Optimize our transfer to the smaller | |||||
if(DataLength < size) { // of what we have or the size of the | |||||
size = DataLength; // provided buffer. This way we ony check | |||||
} // one value in our copy loop ;-) | |||||
int RemainingDataLength = size; // Capture the length of data to xfer. | |||||
while(0 < RemainingDataLength) { // While we have work to do | |||||
*bfr = *ReadPointer; // copy each byte from our ReadBuffer, | |||||
bfr++; ReadPointer++; // move the pointers to the next byte, | |||||
DataLength--; // update our ReadBuffers's DataLength, | |||||
RemainingDataLength--; // and count down the bytes left to xfer. | |||||
} | |||||
return size; // When done, say how much we moved. | |||||
} | |||||
int TCPHost::delimited_receive(char* bfr, int size, char delimiter) { // How to receive delimited data. | |||||
if(ReadBufferIsEmpty()) { // If the read buffer is empty then | |||||
fillReadBuffer(); // fill it first. | |||||
} // Optimize our transfer to the smaller | |||||
if(DataLength < size) { // of what we have or the size of the | |||||
size = DataLength; // provided buffer. This way we ony check | |||||
} // one value in our copy loop ;-) | |||||
int Count = 0; // Keep our byte count in scope. | |||||
bool DelimiterNotReached = true; // Watching for our deliimiter. | |||||
while((Count < size) && DelimiterNotReached) { // While there is work to do... | |||||
*bfr = *ReadPointer; // copy each byte from our ReadBuffer, | |||||
DelimiterNotReached = (delimiter != (*bfr)); // check for the delimiter character, | |||||
bfr++; ReadPointer++; // move the pointers to the next byte, | |||||
DataLength--; // update our ReadBuffers's DataLength, | |||||
Count++; // and count up the bytes we have moved. | |||||
} | |||||
return Count; // When done, say how much we moved. | |||||
} | |||||
// End Platform Agnostic Stuff | |||||
//////////////////////////////////////////////////////////////////////////////// |
// networking.hpp | |||||
// Copyright (C) 2006-2009 MicroNeil Research Corporation. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
//============================================================================== | |||||
// The networking module abstracts network communications and provides a set | |||||
// of objects for handling most tasks. | |||||
// 20080313 _M Refactored to throw proper runtime_error exceptions. | |||||
// Include only once... | |||||
#ifndef M_Networking | |||||
#define M_Networking | |||||
#include <stdexcept> | |||||
#include <iostream> | |||||
#include <string> | |||||
#include <sstream> | |||||
#include <cstring> | |||||
using namespace std; | |||||
#include <cstdlib> | |||||
#include <cstdio> | |||||
#include <cerrno> | |||||
//// Platform specific includes... | |||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | |||||
//// Windows headers... | |||||
#include <winsock2.h> | |||||
typedef int socklen_t; // Posix uses socklen_t so we mimic it. | |||||
typedef SOCKET hSocket; // Winx handles Socket is opaque. | |||||
#else | |||||
//// GNU Headers... | |||||
#include <netdb.h> | |||||
#include <sys/socket.h> | |||||
#include <netinet/in.h> | |||||
#include <sys/file.h> | |||||
#include <arpa/inet.h> | |||||
#include <unistd.h> | |||||
#include <fcntl.h> | |||||
typedef int hSocket; // *nix uses int to handle a Socket. | |||||
const hSocket INVALID_SOCKET = -1; // -1 is the invalid Socket. | |||||
#endif | |||||
//// Handling SIGPIPE ////////////////////////////////////////////////////////// | |||||
#ifndef MSG_NOSIGNAL | |||||
const int MSG_NOSIGNAL = 0; // Fake this if it isn't defined. | |||||
#endif | |||||
#ifndef SO_NOSIGPIPE | |||||
const int SO_NOSIGPIPE = 0; // Fake this if it isn't defined. | |||||
#endif | |||||
//// Tuning and Constants ////////////////////////////////////////////////////// | |||||
const unsigned long LOCALHOST = 0x7F000001; // 127.0.0.1 as an integer. | |||||
const int DefaultMaxPending = 5; // Default connection queue size. | |||||
const int TCPClientBufferSize = 4096; // TCP Client buffer size. | |||||
const int TCPHostBufferSize = 4096; // TCP Host buffer size. | |||||
const int NOFLAGS = 0; // Magic number for no flags. | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// IP4address class | |||||
// | |||||
// The IP4address class makes it easy to manipulate IPs. | |||||
class IP4Address { // IP4Address manipulator. | |||||
private: | |||||
unsigned long int IP; // The actual data. | |||||
public: | |||||
IP4Address(); // Blank constructor IP = 0.0.0.0 | |||||
IP4Address(const unsigned long int newIP); // Constructor given unsigned long | |||||
IP4Address(const IP4Address&); // Constructor given an IP4Address | |||||
IP4Address(const char* newIP); // Construcing with a cstring. | |||||
IP4Address(const string& newIP); // Constructing with a cppstring. | |||||
IP4Address& operator=(const unsigned long int Right); // Convert from unsigned long int. | |||||
IP4Address& operator=(const char* Right); // Convert from c string. | |||||
IP4Address& operator=(const string& Right); // Convert from cpp string. | |||||
operator unsigned long int() const; | |||||
operator string() const; | |||||
bool operator<(const IP4Address Right) const; // < Comparison. | |||||
bool operator>(const IP4Address Right) const; // > Comparison. | |||||
bool operator==(const IP4Address Right) const; // == Comparison. | |||||
bool operator!=(const IP4Address Right) const; // != Comparison. | |||||
bool operator<=(const IP4Address Right) const; // <= Comparison. | |||||
bool operator>=(const IP4Address Right) const; // >= Comparison. | |||||
}; | |||||
/* static unsigned long int& | |||||
operator=(unsigned long int& Out, const IP4Address& In); // Assign to unsigned long | |||||
static string& | |||||
operator=(string& Out, const IP4Address& In); // Assign to cpp string | |||||
*/ | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Network Core class | |||||
// | |||||
// The Networking class acts as a central point for setup, cleanup, and access | |||||
// to network services. For example, when using WinSock, the DLL initialization | |||||
// must occur once when the program starts up and the shutdown must occur once | |||||
// as the program shuts down. The constructor and destructor of the "Network" | |||||
// instances of this class handles that work. There should only be one instance | |||||
// of this class anywhere in the program and that instance is created when this | |||||
// module is included. DON'T MAKE MORE INSTANCES OF THIS :-) | |||||
// | |||||
// Part of the reason for this class is to handle all of the cross-platform | |||||
// weirdness involved in handling sockets and conversions. This way all of the | |||||
// ifdef switched code can be consolidated into this utility class and the | |||||
// code for the remaining classes can remain nice and clean by using this | |||||
// class to handle those tasks. | |||||
class Networking { | |||||
private: | |||||
public: | |||||
class NotSupportedError : public runtime_error { // Thrown when something can't be done. | |||||
public: NotSupportedError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class InitializationError : public runtime_error { // Thrown if initialization fails. | |||||
public: InitializationError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class ControlError : public runtime_error { // Thrown if control functions fail. | |||||
public: ControlError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketCreationError : public runtime_error { // Thrown if a call to socket() fails. | |||||
public: SocketCreationError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketSetSockOptError : public runtime_error { | |||||
public: SocketSetSockOptError(const string& w):runtime_error(w) {} // Thrown if a call to setsockopt() fails. | |||||
}; | |||||
class SocketBindError : public runtime_error { // Thrown if a call to bind() fails. | |||||
public: SocketBindError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketListenError : public runtime_error { // Thrown if a call to listen() fails. | |||||
public: SocketListenError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketConnectError : public runtime_error { // Thrown if a call to connect() fails. | |||||
public: SocketConnectError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketAcceptError : public runtime_error { // Thrown if a call to accept() fails. | |||||
public: SocketAcceptError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketReadError : public runtime_error { // Thrown if a socket read call fails. | |||||
public: SocketReadError(const string& w):runtime_error(w) {} | |||||
}; | |||||
class SocketWriteError : public runtime_error { // Thrown if a socket write call fails. | |||||
public: SocketWriteError(const string& w):runtime_error(w) {} | |||||
}; | |||||
static string DescriptiveError(string Msg, int Errno); // Form a descriptive error w/ errno. | |||||
Networking(); | |||||
~Networking(); | |||||
int getLastError(); // WSAGetLastError or errno | |||||
int setNonBlocking(hSocket socket); // Set socket to non-blocking. | |||||
int closeSocket(hSocket socket); // closesocket() or close() | |||||
bool WouldBlock(int ErrorCode); // ErrorCode matches [WSA]EWOULDBLOCK | |||||
bool InProgress(int ErrorCode); // ErrorCode matches [WSA]EINPROGRESS | |||||
bool IsConnected(int ErrorCode); // ErrorCode matches [WSA]EISCONN | |||||
}; | |||||
extern Networking Network; // There is ONE Network object ;-) | |||||
// End of Network Core Class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// SocketName class | |||||
// This class represents a communications end-point on a TCP/IP network. All | |||||
// conversions from/to strings and for byte orders are handled in this class | |||||
// as well as lookups for ports/services and IPaddresses/host-names. | |||||
// | |||||
// Note that the cstring conversions expect the buffer to be large enough. | |||||
const int IPStringBufferSize = 40; // Safe size for IP as text conversion. | |||||
const int PortStringBufferSize = 20; // Safe size for Port as text conversion. | |||||
class SocketAddress { | |||||
private: | |||||
struct sockaddr_in Address; // Socket address structure. | |||||
char IPStringBuffer[IPStringBufferSize]; // Handy conversion buffer. | |||||
char PortStringBuffer[PortStringBufferSize]; // Handy conversion buffer. | |||||
public: | |||||
SocketAddress(); // Constructor sets ANY address. | |||||
struct sockaddr_in* getPtr_sockaddr_in(); // Returns a pointer to sockaddr_in. | |||||
struct sockaddr* getPtr_sockaddr(); // Returns a pointer to sockaddr. | |||||
socklen_t getAddressSize(); // How big is that structure anyway? | |||||
void setAddress(unsigned long ipAddress); // Set the IP address from an unsigned int | |||||
void setAddress(char* ipString); // Set the IP address from a cstring | |||||
unsigned long getAddress(); // Get the IP address as an unsigned int | |||||
const char* getAddress(char* str); // Get the IP address into a cstring | |||||
void getAddress(int& a0, int& a1, int& a2, int& a3); // Get the IP address into 4 ints | |||||
void setPort(unsigned short port); // Set the port address from an int | |||||
void setPort(char* port); // Set the port address from a cstring | |||||
unsigned short getPort(); // Get the port address as an unsigned int | |||||
const char* getPort(char* str); // Get the port address into a cstring | |||||
void clear(); // Initialize the address. | |||||
}; | |||||
// End of SocketName class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Socket class | |||||
// This class abstracts the underlying socket and adds some functionality | |||||
// for this module. The derived class is expected to setup the socket before | |||||
// it can be opened. In fact, the derivative class must provide the open() | |||||
// function :-) Open is expected to call socket, bind it, and set the socket | |||||
// into the appropriate mode for it's use in the derived object. | |||||
class Socket { | |||||
protected: | |||||
hSocket Handle; // Our socket handle. | |||||
bool NonBlocking; // True if the socket is NonBlocking. | |||||
bool ReuseAddress; // True if SO_REUSEADDR should be used. | |||||
bool OpenSucceeded; // Successful open occurred. | |||||
int LastError; // Last error result for this socket. | |||||
SocketAddress LocalAddress; // Our local address data. | |||||
SocketAddress RemoteAddress; // Our remote address data. | |||||
public: | |||||
Socket(); // Constructor sets initial state. | |||||
virtual ~Socket(); // Destructor closes Socket if open. | |||||
hSocket getHandle(); // Returns the current SocketId. | |||||
bool isNonBlocking(); // Returns true if socket is NonBlocking | |||||
void makeNonBlocking(); // Sets the socket to NonBlocking mode. | |||||
bool isReuseAddress(); // True if socket is set SO_REUSEADDR. | |||||
bool isReuseAddress(bool set); // Changes SO_REUSEADDR setting. | |||||
bool isOpen(); // True if the socket is open. | |||||
int getLastError(); // Returns the last error for this socket. | |||||
virtual void open() = 0; // Derived class specifies open(); | |||||
void close(); // Close politely. | |||||
}; | |||||
// End of Socket class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// MessagePort class | |||||
// Interface that Sends and Receives messages - possibly a bit at a time. This | |||||
// interface standardizes things so that multiple technologies can go beneith | |||||
// such as UNIX domain pipes or named pipes or sockets etc. There is also a | |||||
// special function to improve the efficiency of delimited transfers (such as | |||||
// email). The function checks for the delimited byte inside an optimized loop | |||||
// so that the port doesn't have to be read one byte at a time by the caller. | |||||
// In the case of non-blocking ports, these methods may return before all of | |||||
// the data has been transferred. In these cases the caller is expected to know | |||||
// if it's got the complete message and is expected to repeat it's call until | |||||
// it does. | |||||
class MessagePort { | |||||
public: | |||||
virtual bool isNonBlocking() = 0; // True if we should expect partial xfrs. | |||||
virtual int transmit(const char* bfr, int size) = 0; // How to send a buffer of data. | |||||
virtual int receive(char* bfr, int size) = 0; // How to receive a buffer of data. | |||||
virtual int delimited_receive(char* bfr, int size, char delimiter) = 0; // How to receive delimited data. | |||||
}; | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Message class | |||||
// This is a base class for representing messages that are sent to or received | |||||
// from MessagePorts. The basic Message has 3 modes. Unfixed width, fixed width, | |||||
// or delimeted. More complex messaging schemes can be built up from these | |||||
// basics. A message must know how to send and recieve itself using the | |||||
// MessagePort API and must be able to indicate if the latest transfer request | |||||
// is complete or needs to be continued. The MessagePort may be blocking or | |||||
// non-blocking. If it is blocking then a writeTo() or readFrom() operation | |||||
// should not return until the transfer is completed. If the MessagePort is in | |||||
// a non-blocking mode then writeTo() and readFrom() will do as much as they | |||||
// can before returning but if the transfer was not completed then the app | |||||
// lication may need to transferMore(). | |||||
class Message { | |||||
char* Data; // Pointer to message data. | |||||
int DataBufferSize; // Size of buffer to hold data. | |||||
int DataSize; // Size of Data. | |||||
char* RWPointer; // RW position in buffer. | |||||
bool TransferInProgress; // True if read or write is not complete. | |||||
bool Delimited; // Delimited Message Flag. | |||||
char Delimiter; // Delimiter character. | |||||
public: | |||||
/** All of this is yet to be built! **/ | |||||
Message(const Message& M); // Copy constructor. | |||||
Message(int Size); // Construct empty of Size. | |||||
Message(int Size, char Delimiter); // Construct empty with delimiter. | |||||
Message(char* NewData, int Size); // Construct non-delimited message. | |||||
Message(char* NewData, int Size, char Delimiter); // Construct delimited message. | |||||
void writeTo(MessagePort &P); // Initiate an outbound transfer. | |||||
void readFrom(MessagePort &P); // Initiate an inbound transfer. | |||||
bool isBusy(); // True if the transfer isn't complete. | |||||
void transferMore(); // Do more of the transfer. | |||||
void abortTransfer(); // Forget about the transfer. | |||||
bool isDelimited(); // True if the message is delimited. | |||||
char getDelimiter(); // Read the delimiter cahracter. | |||||
char* getData(); // Access the data buffer. | |||||
int getDataSize(); // How much data is there. | |||||
}; | |||||
// End of Message class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// TCPListener class | |||||
// This class represents a local socket used to listen for new connections. The | |||||
// application can poll this object for new inbound connections which are then | |||||
// delivered as TCPClient objects. | |||||
class TCPClient; // Hint about the coming client class. | |||||
class TCPListener : public Socket { | |||||
private: | |||||
bool OpenStage1Complete; // First stage of open() complete. | |||||
bool OpenStage2Complete; // Second stage of open() complete. | |||||
public: | |||||
TCPListener(unsigned short Port); // Set up localhost on this Port. | |||||
TCPListener(SocketAddress& WhereToBind); // Set up specific "name" for listening. | |||||
~TCPListener(); // Close when destructing. | |||||
int MaxPending; // Maximum inbound connection queue. | |||||
virtual void open(); // Open when ready. | |||||
TCPClient* acceptClient(); // Accept a client connection. | |||||
}; | |||||
// End of TCPListener class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// TCPClient class | |||||
// This class represents a TCP network client connection. It is created by | |||||
// a TCPListener object if/when a TCP connection is made to the Listener and | |||||
// accepted by the application. | |||||
class TCPClient : public Socket, public MessagePort { | |||||
private: | |||||
TCPListener& MyListener; | |||||
char ReadBuffer[TCPClientBufferSize]; // Buffer for delimited reading. | |||||
char* ReadPointer; // Read position. | |||||
int DataLength; // Length of data in buffer. | |||||
bool ReadBufferIsEmpty(); // True if DataLength is zero. | |||||
void fillReadBuffer(); // Fill the ReadBuffer from the socket. | |||||
public: | |||||
TCPClient(TCPListener& L, hSocket H, SocketAddress& A); // How to create a TCPClient. | |||||
~TCPClient(); // Destructor for cleanup. | |||||
TCPListener& getMyListener(); // Where did I come from? | |||||
bool isNonBlocking(); // Provided for MessagePort. | |||||
virtual int transmit(const char* bfr, int size); // How to send a buffer of data. | |||||
virtual int receive(char* bfr, int size); // How to receive a buffer of data. | |||||
virtual int delimited_receive(char* bfr, int size, char delimiter); // How to receive delimited data. | |||||
virtual void open(); // We provide open() as unsupported. | |||||
unsigned long getRemoteIP(); // Get remote IP as long. | |||||
const char* getRemoteIP(char* str); // Get IP as string. | |||||
unsigned short getRemotePort(); // Get remote Port as unsigned short. | |||||
const char* getRemotePort(char* str); // Get Port as string. | |||||
}; | |||||
// End of TCPClient class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// TCPHost class | |||||
// This class represents a TCP network server connection. A client application | |||||
// creates this object when it wants to connect to a given TCP service. | |||||
class TCPHost : public Socket, public MessagePort { | |||||
private: | |||||
char ReadBuffer[TCPHostBufferSize]; // Buffer for delimited reading. | |||||
char* ReadPointer; // Read position. | |||||
int DataLength; // Length of data in buffer. | |||||
bool ReadBufferIsEmpty(); // True if DataLength is zero. | |||||
void fillReadBuffer(); // Fill the ReadBuffer from the socket. | |||||
bool OpenStage1Complete; // Skip stage 1 of open() after done. | |||||
public: | |||||
TCPHost(unsigned short Port); // Will connect to localhost on Port. | |||||
TCPHost(SocketAddress& Remote); // Will connect to Remote address/port. | |||||
// TCPHost(SocketAddress& Local, SocketAddress& Remote); // Will connect to Remote from Local. | |||||
~TCPHost(); // Clean up when we go away. | |||||
bool isNonBlocking(); // Provided for MessagePort. | |||||
virtual int transmit(const char* bfr, int size); // How to send a buffer of data. | |||||
virtual int receive(char* bfr, int size); // How to receive a buffer of data. | |||||
virtual int delimited_receive(char* bfr, int size, char delimiter); // How to receive delimited data. | |||||
virtual void open(); // We provide open(). | |||||
}; | |||||
// End of TCPHost class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// UDPListener class | |||||
// This class represents a local UPD port set up to listen for UDP requests. In | |||||
// this case, each UDP packet that arrives is assumed to be a single request so | |||||
// for each a UDPRequest object is created that links back to this Listener. | |||||
// The application can then use that UDPRequest to .respond() with a Message. | |||||
// the response is sent back to the original requester and the UDPRequest is | |||||
// considered satisfied. | |||||
class UDPListener : public Socket { | |||||
}; | |||||
// End of UDPListener class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// UDPRequest class | |||||
// This class is created by a UDPListener when a packet is received. The object | |||||
// contains all of the necessary information about the source for the request | |||||
// so that the application can .respond() to them through this object. The | |||||
// response UDP packtes are sent through the UDPListener socket. | |||||
class UDPRequest : public MessagePort { | |||||
}; | |||||
// End of UDPRequest class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// UDPHost class | |||||
// This class represents a server/host on the network that uses the UDP | |||||
// protocol. The application can use this object to send a .request() Message | |||||
// and getReply(). Each request becomes a UDP packet. Each received UDP packet | |||||
// from the specified UDPHost becomes a reply Message. (Connected UDP socket). | |||||
class UDPHost : public Socket, public MessagePort { | |||||
}; | |||||
// End of UDPHost class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// UDPReceiver class | |||||
// This class is used to receive UDP packets on a particular port, but does not | |||||
// create UDPRequest objects from them - they are considered to be simply | |||||
// Messages. A UDPReceiver is most likely to be used in ad-hoc networking and | |||||
// to receive advertisements and/or broadcasts from other peers. | |||||
class UDPReceiver : public Socket, public MessagePort { | |||||
}; | |||||
// End of UDPReceiver class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// UDPBroadcaster class | |||||
// This class is used to advertise / broadcast Messages using UDP. | |||||
class UDPBroadcaster : public Socket, public MessagePort { | |||||
}; | |||||
// End of UDPBroadcaster class | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//// Include Inline methods and functions... | |||||
#include "networking.inline.hpp" | |||||
#endif | |||||
// End include Networking.hpp only once... |
// networking.inline.hpp | |||||
// Copyright (C) 2006-2009 MicroNeil Research Corporation. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
//============================================================================== | |||||
// Inlined methods for Networking module. See networking.hpp for notes. | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Platform Specific | |||||
//// Windows platform | |||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | |||||
inline int Networking::getLastError() { // In windows you get the last error | |||||
return WSAGetLastError(); // from WSAGetLastError(); | |||||
} | |||||
inline int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking | |||||
unsigned long nonblocking = 1; // Create a flag... | |||||
int result = 0; | |||||
if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket. | |||||
result = -1; // If that fails then return -1. | |||||
} | |||||
return result; // Show 'em my motto! | |||||
} | |||||
inline int Networking::closeSocket(hSocket socket) { // Close a socket in winsock | |||||
return closesocket(socket); // wraps closesocket(). | |||||
} | |||||
inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK. | |||||
return (WSAEWOULDBLOCK == ErrorCode); | |||||
} | |||||
inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS. | |||||
return( // [WSA]EALREADY also returns true. | |||||
WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could | |||||
WSAEALREADY == ErrorCode || // get any of these when retesting | |||||
WSAEWOULDBLOCK == ErrorCode || // open() for a connection. | |||||
WSAEINVAL == ErrorCode | |||||
); | |||||
} | |||||
inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN. | |||||
return(WSAEISCONN == ErrorCode); | |||||
} | |||||
#else | |||||
//// GNU platform | |||||
inline int Networking::getLastError() { // In GNU you get the last error | |||||
return errno; // from errno; | |||||
} | |||||
inline int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking | |||||
int flags, result; // Grab a place to hold the flags. | |||||
flags = fcntl(socket, F_GETFL, 0); // Get the current flags. | |||||
result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return. | |||||
return result; // Return the result. | |||||
} | |||||
inline int Networking::closeSocket(hSocket socket) { // Close a socket in GNU | |||||
return close(socket); // wraps close(). | |||||
} | |||||
inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK. | |||||
return (EWOULDBLOCK == ErrorCode); | |||||
} | |||||
inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS. | |||||
return( // [WSA]EALREADY also returns true. | |||||
EINPROGRESS == ErrorCode || | |||||
EALREADY == ErrorCode | |||||
); | |||||
} | |||||
inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN. | |||||
return(EISCONN == ErrorCode); | |||||
} | |||||
#endif | |||||
// End Platform Specific | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Begin Platform Agnostic | |||||
//// class IP4Address ////////////////////////////////////////////////////////// | |||||
inline IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0 | |||||
inline IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long | |||||
inline IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address | |||||
inline IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring. | |||||
inline IP4Address::IP4Address(const string& newIP) { (*this) = newIP; } // Constructing with a cppstring. | |||||
inline IP4Address& | |||||
IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int. | |||||
IP = Right; | |||||
return *this; | |||||
} | |||||
inline IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string. | |||||
IP = ntohl(inet_addr(Right)); | |||||
return *this; | |||||
} | |||||
inline IP4Address& IP4Address::operator=(const string& Right) { // Convert from cpp string. | |||||
IP = ntohl(inet_addr(Right.c_str())); | |||||
return *this; | |||||
} | |||||
inline bool IP4Address::operator<(const IP4Address Right) const { // < Comparison. | |||||
return (IP < Right.IP); | |||||
} | |||||
inline bool IP4Address::operator>(const IP4Address Right) const { // > Comparison. | |||||
return (IP > Right.IP); | |||||
} | |||||
inline bool IP4Address::operator==(const IP4Address Right) const { // == Comparison. | |||||
return (IP == Right.IP); | |||||
} | |||||
inline bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison. | |||||
return (IP != Right.IP); | |||||
} | |||||
inline bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison. | |||||
return (IP <= Right.IP); | |||||
} | |||||
inline bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison. | |||||
return (IP >= Right.IP); | |||||
} | |||||
//// class SocketAddress /////////////////////////////////////////////////////// | |||||
inline void SocketAddress::clear() { | |||||
memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture | |||||
Address.sin_family = AF_INET; // Internet Address Family ip4 | |||||
Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address | |||||
Address.sin_port = 0; // Zero means any port. | |||||
} | |||||
inline SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards | |||||
clear(); // Conveniently, we can use clear() :-) | |||||
} | |||||
inline struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in. | |||||
return &Address; // Simply return it's address. | |||||
} | |||||
inline struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr. | |||||
return (struct sockaddr*) &Address; | |||||
} | |||||
inline socklen_t SocketAddress::getAddressSize() { | |||||
return sizeof(Address); // Return the size of the structure. | |||||
} | |||||
inline void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int | |||||
Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign. | |||||
} | |||||
inline void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring | |||||
Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign. | |||||
} | |||||
inline unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int | |||||
return ntohl(Address.sin_addr.s_addr); // Convert to host order and return. | |||||
} | |||||
inline void SocketAddress::setPort(unsigned short port) { // Set the port address from an int | |||||
Address.sin_port = htons(port); // Convert to network order and set. | |||||
} | |||||
inline void SocketAddress::setPort(char* port) { // Set the port address from a cstring | |||||
setPort(atoi(port)); // Convert to int and set. | |||||
} | |||||
inline unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int | |||||
return ntohs(Address.sin_port); // Convert to host order and return. | |||||
} | |||||
inline const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring. | |||||
if(NULL == str) { // If the caller did not provide a | |||||
str = PortStringBuffer; // buffer to use then we will use ours. | |||||
} | |||||
sprintf(str,"%d",getPort()); // Get the port and convert to cstring. | |||||
return str; // Return the string we got. | |||||
} | |||||
//// class Socket ////////////////////////////////////////////////////////////// | |||||
inline Socket::Socket() : // When starting up we are | |||||
Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid. | |||||
} | |||||
inline Socket::~Socket() { // When shutting down, be sure | |||||
if(INVALID_SOCKET != Handle) { // any open socket is closed without | |||||
Network.closeSocket(Handle); // throwing any exceptions. | |||||
} | |||||
} | |||||
inline void Socket::close() { // When we close, | |||||
if(INVALID_SOCKET != Handle) { // If the handle is open then | |||||
if(Network.closeSocket(Handle)) { // close the handle and check for error. | |||||
LastError = Network.getLastError(); // If there was an error record it. | |||||
if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK | |||||
throw Networking::ControlError( // then throw a ControlError exception. | |||||
Network.DescriptiveError( | |||||
"Socket::close()", LastError)); | |||||
} | |||||
} else { // If there was no error then | |||||
LastError = 0; // reset the LastError value. | |||||
} | |||||
Handle = INVALID_SOCKET; // and reset the handle to INVALID. | |||||
NonBlocking = false; // The default is Blocking. | |||||
OpenSucceeded = false; // After close, forget we opened. | |||||
} | |||||
} | |||||
inline hSocket Socket::getHandle() { // Returns the current Socket handle. | |||||
return Handle; | |||||
} | |||||
inline bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking | |||||
return NonBlocking; | |||||
} | |||||
inline void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode. | |||||
if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network. | |||||
LastError = Network.getLastError(); // If it didn't work, go get the error. | |||||
NonBlocking = false; // We are NOT NonBlocking. | |||||
throw Networking::ControlError( // Throw a control error. | |||||
Network.DescriptiveError( | |||||
"Socket::makeNonBlocking()", LastError)); | |||||
} else { | |||||
NonBlocking = true; // If we didn't throw, we're ON. | |||||
} | |||||
} | |||||
inline bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR. | |||||
inline bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting. | |||||
inline bool Socket::isOpen() { // True if the socket is open. | |||||
return( | |||||
INVALID_SOCKET != Handle && // A valid handle and | |||||
true == OpenSucceeded // a successful open operation | |||||
); // means we're open. | |||||
} | |||||
inline int Socket::getLastError() { // Returns the last error for this socket. | |||||
return LastError; | |||||
} | |||||
//// class TCPClient /////////////////////////////////////////////////////////// | |||||
inline TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient. | |||||
MyListener(L) { // Capture our listener. | |||||
Handle = H; // Capture the new socket handle. | |||||
RemoteAddress = A; // Capture the client address. | |||||
ReadPointer = ReadBuffer; // Set the read position to zero. | |||||
DataLength = 0; // There is no data yet. | |||||
OpenSucceeded = true; // We're getting an open socket. | |||||
} | |||||
inline TCPClient::~TCPClient() { // When destroying a TCPClient | |||||
try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections. | |||||
} | |||||
inline void TCPClient::open() { // We provide open() as unsupported. | |||||
throw Networking::NotSupportedError( // Throw an exception if this is called. | |||||
Network.DescriptiveError( | |||||
"TCPClient::open()", LastError)); | |||||
} | |||||
inline bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty. | |||||
return (0 >= DataLength); // We can check that with DataLength. | |||||
} | |||||
inline void TCPClient::fillReadBuffer() { // Fills the buffer from the socket. | |||||
LastError = 0; // Clear the LastError value. | |||||
ReadPointer = ReadBuffer; // Reset the ReadPointer. | |||||
DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data. | |||||
if(0 >= DataLength) { // If there was an error then | |||||
LastError = Network.getLastError(); // Grab the last error code. | |||||
DataLength = 0; // Correct the DataLength. | |||||
if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
return; // simply return - it's ok. | |||||
} else { // If it was a different error | |||||
throw Networking::SocketReadError( // then throw a ReadError. | |||||
Network.DescriptiveError( | |||||
"TCPClient::fillReadBuffer()", LastError)); | |||||
} | |||||
} // If we succeeded then our ReadBuffer | |||||
} // assembly is in good shape. | |||||
inline bool TCPClient::isNonBlocking() { // Provided for MessagePort. | |||||
return Socket::isNonBlocking(); | |||||
} | |||||
inline unsigned long TCPClient::getRemoteIP() { // Get remote IP as long. | |||||
return RemoteAddress.getAddress(); | |||||
} | |||||
inline const char* TCPClient::getRemoteIP(char* str) { // Get IP as string. | |||||
return RemoteAddress.getAddress(str); | |||||
} | |||||
inline unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short. | |||||
return RemoteAddress.getPort(); | |||||
} | |||||
inline const char* TCPClient::getRemotePort(char* str) { // Get Port as string. | |||||
return RemoteAddress.getPort(str); | |||||
} | |||||
//// class TCPHost ///////////////////////////////////////////////////////////// | |||||
inline TCPHost::~TCPHost() { // When destroying a TCPHost | |||||
try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection. | |||||
} | |||||
inline bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty. | |||||
return (0 >= DataLength); // We can check that with DataLength. | |||||
} | |||||
inline void TCPHost::fillReadBuffer() { // Fills the buffer from the socket. | |||||
LastError = 0; // Clear the LastError value. | |||||
ReadPointer = ReadBuffer; // Reset the ReadPointer. | |||||
DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data. | |||||
if(0 >= DataLength) { // If there was an error then | |||||
LastError = Network.getLastError(); // Grab the last error code. | |||||
DataLength = 0; // Correct the DataLength. | |||||
if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
return; // simply return - it's ok. | |||||
} else { // If it was a different error | |||||
throw Networking::SocketReadError( // then throw a ReadError. | |||||
Network.DescriptiveError( | |||||
"TCPHost::fillReadBuffer()", LastError)); | |||||
} | |||||
} // If we succeeded then our ReadBuffer | |||||
} // assembly is in good shape. | |||||
inline bool TCPHost::isNonBlocking() { // Provided for MessagePort. | |||||
return Socket::isNonBlocking(); | |||||
} | |||||
//// class TCPListener ///////////////////////////////////////////////////////// | |||||
inline TCPListener::~TCPListener() { // When destroying a TCPListener | |||||
try{ close(); } catch(...) {} // silently close if not already done. | |||||
} |
// threading.cpp | |||||
// | |||||
// (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
// For details on the Threading module and development history see threading.hpp | |||||
#include "threading.hpp" | |||||
using namespace std; // Introduce std namespace. | |||||
ThreadManager Threads; // Master thread manager. | |||||
void ThreadManager::rememberThread(Thread* T) { // Threads register themselves. | |||||
ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect the known pool. | |||||
KnownThreads.insert(T); // Add the new thread pointer. | |||||
} | |||||
void ThreadManager::forgetThread(Thread* T) { // Threads remove themselves. | |||||
ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect the known pool. | |||||
KnownThreads.erase(T); // Add the new thread pointer. | |||||
} | |||||
ThreadStatusReport ThreadManager::StatusReport() { // Get a status report, All Threads. | |||||
ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect our set -- a moment in time. | |||||
ThreadStatusReport Answer; // Create our vector to hold the report. | |||||
for( // Loop through all of the Threads. | |||||
set<Thread*>::iterator iT = KnownThreads.begin(); | |||||
iT != KnownThreads.end(); iT++ | |||||
) { // Grab each Threads' report. | |||||
Thread& X = *(*iT); // Handy reference to the Thread. | |||||
Answer.push_back(X.StatusReport()); // Push back each Thread's report. | |||||
} | |||||
return Answer; // Return the finished report. | |||||
} | |||||
bool ThreadManager::lockExistingThread(Thread* T) { // Locks ThreadManager if T exists. | |||||
MyMutex.lock(); // Lock the mutex for everyone. | |||||
if(KnownThreads.end() == KnownThreads.find(T)) { // If we do not find T in our set | |||||
MyMutex.unlock(); // then unlock the mutex and return | |||||
return false; // false. | |||||
} // If we did find it then | |||||
LockedThread = T; // set our locked thread and | |||||
return true; // return true; | |||||
} | |||||
const RuntimeCheck ThreadingCheck1("ThreadManager::unlockExistingThread():ThreadingCheck1(0 != LockedThread)"); | |||||
const RuntimeCheck ThreadingCheck2("ThreadManager::unlockExistingThread():ThreadingCheck2(T == LockedThread)"); | |||||
void ThreadManager::unlockExistingThread(Thread* T) { // Unlocks ThreadManager if T locked. | |||||
ThreadingCheck1(0 != LockedThread); // We had better have a locked thread. | |||||
ThreadingCheck2(T == LockedThread); // The locked thread had better match. | |||||
LockedThread = 0; // Clear the locked thread. | |||||
MyMutex.unlock(); // Unlock the mutex. | |||||
} | |||||
//// Scope Thread Lock allows for a safe way to lock threads through the Threads | |||||
//// object for delivering short messages. Just like a ScopeMutex, when the object | |||||
//// goes away the lock is released. | |||||
ScopeThreadLock::ScopeThreadLock(Thread* T) : // Construct a scope lock on a Thread. | |||||
MyLockedThread(0) { // To star with we have no lock. | |||||
if(Threads.lockExistingThread(T)) { // If we achieve a lock then we | |||||
MyLockedThread = T; // remember it. Our destructor will | |||||
} // unlock it if we were successful. | |||||
} | |||||
ScopeThreadLock::~ScopeThreadLock() { // Destruct a scope lock on a Thread. | |||||
if(0 != MyLockedThread) { // If we were successfully constructed | |||||
Threads.unlockExistingThread(MyLockedThread); // we can unlock the thread and | |||||
MyLockedThread = 0; // forget about it before we go away. | |||||
} | |||||
} | |||||
bool ScopeThreadLock::isGood() { // If we have successfully locked T | |||||
return (0 != MyLockedThread) ? true:false; // it will NOT be 0, so return true. | |||||
} | |||||
bool ScopeThreadLock::isBad() { // If we did not successfully lock T | |||||
return (0 == MyLockedThread) ? false:true; // it will be 0, so return false. | |||||
} | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Thread | |||||
const ThreadType Thread::Type("Generic Thread"); | |||||
const ThreadState Thread::ThreadInitialized("Thread Initialized"); | |||||
const ThreadState Thread::ThreadStarted("Thread Started"); | |||||
const ThreadState Thread::ThreadFailed("Thread Failed"); | |||||
const ThreadState Thread::ThreadStopped("Thread Stopped"); | |||||
const ThreadState Thread::ThreadDestroyed("Thread Destroyed"); | |||||
bool Thread::isRunning() { return RunningFlag; } // Return RunningFlag state. | |||||
bool Thread::isBad() { return BadFlag; } // Return BadFlag state. | |||||
const string Thread::MyFault() { return BadWhat; } // Return exception Bad fault if any. | |||||
const string Thread::MyName() { return MyThreadName; } // Return the instance name if any. | |||||
const ThreadType& Thread::MyType() { return MyThreadType; } // Return the instance Thread Type. | |||||
const ThreadState& Thread::MyState() { return (*MyThreadState); } // Thread state for this instance. | |||||
void Thread::CurrentThreadState(const ThreadState& TS) { // Set Current Thread State. | |||||
MyThreadState = const_cast<ThreadState*>(&TS); | |||||
} | |||||
const ThreadState& Thread::CurrentThreadState() { return (*MyThreadState); } // Get Current Thread State. | |||||
ThreadStatusRecord Thread::StatusReport() { // Get a status report from this thread. | |||||
return | |||||
ThreadStatusRecord( // Status record. | |||||
this, | |||||
const_cast<ThreadType&>(MyThreadType), | |||||
*MyThreadState, | |||||
RunningFlag, | |||||
BadFlag, | |||||
BadWhat, | |||||
MyThreadName | |||||
); | |||||
} | |||||
// launchTask() calls and monitors myTask for exceptions and set's the correct | |||||
// states for the isBad and isRunning flags. | |||||
void Thread::launchTask() { // Launch and watch myTask() | |||||
try { // Do this safely. | |||||
RunningFlag = true; // Now we are running. | |||||
CurrentThreadState(ThreadStarted); // Set the running state. | |||||
myTask(); // myTask() is called. | |||||
} // myTask() should handle exceptions. | |||||
catch(exception& e) { // Unhandled exceptions are informative: | |||||
BadFlag = true; // They mean the thread went bad but | |||||
BadWhat = e.what(); // we have an idea what went wrong. | |||||
} // We shouldn't get other kinds of | |||||
catch(...) { // exceptions because if things go | |||||
BadFlag = true; // wrong and one gets through this | |||||
BadWhat = "Unkown Exception(...)"; // is all we can say about it. | |||||
} | |||||
RunningFlag = false; // When we're done, we're done. | |||||
if(BadFlag) CurrentThreadState(ThreadFailed); // If we're bad we failed. | |||||
else CurrentThreadState(ThreadStopped); // If we're not bad we stopped. | |||||
} | |||||
// getMyThread() returns the local thread primative. | |||||
thread_primative Thread::getMyThread() { return MyThread; } // Return my thread primative. | |||||
// runThreadTask() is a helper function to start threads. It is the function | |||||
// that is acutally launched as a new thread. It's whole job is to call the | |||||
// myTask() method on the object passed to it as it is launched. | |||||
// The run() method creates a new thread with ThreadRunner() as the main | |||||
// function, having passed it's object. | |||||
// WIN32 and POSIX have different versions of both the main thread function | |||||
// and the way to launch it. | |||||
#ifdef WIN32 | |||||
Thread::Thread() : // When constructing a WIN32 thread | |||||
MyThreadType(Thread::Type), // Use generic Thread Type. | |||||
MyThreadName("UnNamed Thread"), // Use a generic Thread Name. | |||||
MyThread(NULL), // Null the thread handle. | |||||
RunningFlag(false), // Couldn't be running yet. | |||||
BadFlag(false) { // Couldn't be bad yet. | |||||
Threads.rememberThread(this); // Remember this thread. | |||||
CurrentThreadState(ThreadInitialized); // Set our initialized state. | |||||
} | |||||
Thread::Thread(const ThreadType& T, const string N) : // Construct with specific Type/Name | |||||
MyThreadType(T), // Use generic Thread Type. | |||||
MyThreadName(N), // Use a generic Thread Name. | |||||
MyThread(NULL), // Null the thread handle. | |||||
RunningFlag(false), // Couldn't be running yet. | |||||
BadFlag(false) { // Couldn't be bad yet. | |||||
Threads.rememberThread(this); // Remember this thread. | |||||
CurrentThreadState(ThreadInitialized); // Set our initialized state. | |||||
} | |||||
Thread::~Thread() { // In WIN32 land when we destroy the | |||||
if(NULL != MyThread) { // thread object check for a valid | |||||
CloseHandle(MyThread); // thread handle and destroy it if | |||||
} // it exists. | |||||
RunningFlag = false; // The thread is not running. | |||||
Threads.forgetThread(this); // Forget this thread. | |||||
CurrentThreadState(ThreadDestroyed); // The Thread has left the building. | |||||
} | |||||
unsigned __stdcall runThreadTask(void* thread_object) { // The WIN32 version has this form. | |||||
((Thread*)thread_object)->launchTask(); // Run the task. | |||||
_endthreadex(0); // Signal the thread is finished. | |||||
return 0; // Satisfy the unsigned return. | |||||
} | |||||
void Thread::run() { // Run a WIN32 thread... | |||||
unsigned tid; // Thread id to toss. Only need Handle. | |||||
MyThread = (HANDLE) _beginthreadex(NULL,0,runThreadTask,this,0,&tid); // Create a thread calling ThreadRunner | |||||
if(NULL == MyThread) BadFlag = true; // and test that the resutl was valid. | |||||
} | |||||
void Thread::join() { // To join in WIN32 | |||||
WaitForSingleObject(MyThread, INFINITE); // Wait for the thread by handle. | |||||
} | |||||
#else | |||||
Thread::Thread() : // POSIX Thread constructor. | |||||
MyThreadType(Thread::Type), // Use a generic Thread Type. | |||||
MyThreadName("UnNamed Thread"), // Use a generic Thread Name. | |||||
RunningFlag(false), // Can't be running yet. | |||||
BadFlag(false) { // Can't be bad yet. | |||||
Threads.rememberThread(this); // Remember this thread. | |||||
CurrentThreadState(ThreadInitialized); // Set our initialized state. | |||||
} | |||||
Thread::Thread(const ThreadType& T, const string N) : // POSIX Specific Thread Constructor. | |||||
MyThreadType(T), // Use a generic Thread Type. | |||||
MyThreadName(N), // Use a generic Thread Name. | |||||
RunningFlag(false), // Can't be running yet. | |||||
BadFlag(false) { // Can't be bad yet. | |||||
Threads.rememberThread(this); // Remember this thread. | |||||
CurrentThreadState(ThreadInitialized); // Set our initialized state. | |||||
} | |||||
Thread::~Thread() { // POSIX destructor. | |||||
RunningFlag = false; // Not running now for sure. | |||||
Threads.forgetThread(this); // Forget this thread. | |||||
CurrentThreadState(ThreadDestroyed); // The Thread has left the building. | |||||
} | |||||
void* runThreadTask(void* thread_object) { // The POSIX version has this form. | |||||
((Thread*)thread_object)->launchTask(); | |||||
return NULL; | |||||
} | |||||
void Thread::run() { // Run a POSIX thread... | |||||
int result = pthread_create(&MyThread, NULL, runThreadTask, this); // Create a thread calling ThreadRunner | |||||
if(0 != result) BadFlag = true; // and test that there was no error. | |||||
} | |||||
void Thread::join() { // To join in POSIX | |||||
pthread_join(MyThread, NULL); // call pthread_join with MyThread. | |||||
} | |||||
#endif | |||||
// End Thread | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Mutex | |||||
#ifdef WIN32 | |||||
// WIN32 Mutex Implementation ////////////////////////////////////////////////// | |||||
// The original design of the WIN32 Mutex used critical sections. However after | |||||
// additional research it was determined that the use of a Semaphore with an | |||||
// initial count of 1 would work better overall on multiple Winx platforms - | |||||
// especially SMP systems. | |||||
const RuntimeCheck ThreadingCheck3("Mutex::Mutex():ThreadingCheck3(NULL != MyMutex)"); | |||||
Mutex::Mutex() : // Creating a WIN32 Mutex means | |||||
IAmLocked(false) { // Setting IAmLocked to false and | |||||
MyMutex = CreateSemaphore(NULL, 1, 1, NULL); // create a semaphore object with | |||||
ThreadingCheck3(NULL != MyMutex); // a count of 1. | |||||
} | |||||
const ExitCheck ThreadingCheck4("Mutex::~Mutex():"); | |||||
Mutex::~Mutex() { // Destroying a WIN32 Mutex means | |||||
ThreadingCheck4(false == IAmLocked); // Make sure we're not in use and | |||||
CloseHandle(MyMutex); // destroy the semaphore object. | |||||
} | |||||
bool Mutex::tryLock() { // Trying to lock WIN32 Mutex means | |||||
bool DoIHaveIt = false; // Start with a pessimistic assumption | |||||
if( | |||||
false == IAmLocked && // If we have a shot at this and | |||||
WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, 0) // we actually get hold of the semaphore | |||||
) { // then we can set our flags... | |||||
IAmLocked = true; // Set IAmLocked, because we are and | |||||
DoIHaveIt = true; // set our result to true. | |||||
} | |||||
return DoIHaveIt; // Return true if we got it (see above). | |||||
} | |||||
const RuntimeCheck ThreadingCheck5("Mutex::lock():ThreadingCheck5(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE))"); | |||||
void Mutex::lock() { // Locking the WIN32 Mutex means | |||||
ThreadingCheck5(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE)); // Wait on the semaphore - only 1 will | |||||
IAmLocked = true; // get through or we have a big problem. | |||||
} | |||||
const LogicCheck ThreadingCheck6("Mutex::unlock():ThreadingCheck6(true == IAmLocked)"); | |||||
void Mutex::unlock() { // Unlocking the WIN32 Mutex means | |||||
ThreadingCheck6(true == IAmLocked); // making sure we're really locked then | |||||
IAmLocked = false; // reset the IAmLocked flag and | |||||
ReleaseSemaphore(MyMutex, 1, NULL); // release the semaphore. | |||||
} | |||||
bool Mutex::isLocked() { return IAmLocked; } // Return the IAmLocked flag. | |||||
#else | |||||
// POSIX Mutex Implementation ////////////////////////////////////////////////// | |||||
const RuntimeCheck ThreadingCheck7("Mutex::Mutex():ThreadingCheck7(0 == pthread_mutex_init(&MyMutex,NULL))"); | |||||
Mutex::Mutex() : // Constructing a POSIX mutex means | |||||
IAmLocked(false) { // setting the IAmLocked flag to false and | |||||
ThreadingCheck7(0 == pthread_mutex_init(&MyMutex,NULL)); // initializing the mutex_t object. | |||||
} | |||||
const ExitCheck ThreadingCheck8("Mutex::~Mutex():ThreadingCheck8(false == IAmLocked)"); | |||||
const ExitCheck ThreadingCheck9("Mutex::~Mutex():ThreadingCheck9(0 == pthread_mutex_destroy(&MyMutex))"); | |||||
Mutex::~Mutex() { // Before we destroy our mutex we check | |||||
ThreadingCheck8(false == IAmLocked); // to see that it is not locked and | |||||
ThreadingCheck9(0 == pthread_mutex_destroy(&MyMutex)); // destroy the primative. | |||||
} | |||||
const RuntimeCheck ThreadingCheck10("Mutex::lock():ThreadingCheck10(0 == pthread_mutex_lock(&MyMutex));"); | |||||
void Mutex::lock() { // Locking a POSIX mutex means | |||||
ThreadingCheck10(0 == pthread_mutex_lock(&MyMutex)); // asserting our lock was successful and | |||||
IAmLocked = true; // setting the IAmLocked flag. | |||||
} | |||||
const LogicCheck ThreadingCheck11("Mutex::unlock():ThreadingCheck11(true == IAmLocked)"); | |||||
const RuntimeCheck ThreadingCheck12("Mutex::unlock():ThreadingCheck12(0 == pthread_mutex_unlock(&MyMutex))"); | |||||
void Mutex::unlock() { // Unlocking a POSIX mutex means | |||||
ThreadingCheck11(true == IAmLocked); // asserting that we are locked, | |||||
IAmLocked = false; // clearing the IAmLocked flag, and | |||||
ThreadingCheck12(0 == pthread_mutex_unlock(&MyMutex)); // unlocking the actual mutex. | |||||
} | |||||
bool Mutex::tryLock() { // Trying to lock a POSIX mutex means | |||||
bool DoIHaveIt = false; // starting off pessimistically. | |||||
if(false == IAmLocked) { // If we are not locked yet then we | |||||
if(0 == pthread_mutex_trylock(&MyMutex)) { // try to lock the mutex. If we succeed | |||||
IAmLocked = true; // we set our IAmLocked flag and our | |||||
DoIHaveIt = true; // DoIHaveIt flag to true; | |||||
} | |||||
} | |||||
return DoIHaveIt; // In any case we return the result. | |||||
} | |||||
bool Mutex::isLocked() { return IAmLocked; } // Return the IAmLocked flag. | |||||
#endif | |||||
// End Mutex | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// ScopeMutex | |||||
ScopeMutex::ScopeMutex(Mutex& M) : // When constructing a ScopeMutex, | |||||
MyMutex(M) { // Initialize MyMutex with what we are given | |||||
MyMutex.lock(); // and then immediately lock it. | |||||
} | |||||
ScopeMutex::~ScopeMutex() { // When a ScopeMutex is destroyed, | |||||
MyMutex.unlock(); // it first unlocks it's mutex. | |||||
} | |||||
// End ScopeMutex | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Production Gateway | |||||
#ifdef WIN32 | |||||
// Win32 Implementation //////////////////////////////////////////////////////// | |||||
const RuntimeCheck ThreadingCheck13("ProductionGateway::ProductionGateway():ThreadingCheck13(NULL != MySemaphore)"); | |||||
ProductionGateway::ProductionGateway() { // Construct in Windows like this: | |||||
const int HUGENUMBER = 0x7fffffL; // Work without any real limits. | |||||
MySemaphore = CreateSemaphore(NULL, 0, HUGENUMBER, NULL); // Create a Semaphore for signalling. | |||||
ThreadingCheck13(NULL != MySemaphore); // That should always work. | |||||
} | |||||
ProductionGateway::~ProductionGateway() { // Be sure to close it when we're done. | |||||
CloseHandle(MySemaphore); | |||||
} | |||||
void ProductionGateway::produce() { // To produce() in WIN32 we | |||||
ReleaseSemaphore(MySemaphore, 1, NULL); // release 1 count into the semaphore. | |||||
} | |||||
void ProductionGateway::consume() { // To consume() in WIN32 we | |||||
WaitForSingleObject(MySemaphore, INFINITE); // wait for a count in the semaphore. | |||||
} | |||||
#else | |||||
// POSIX Implementation //////////////////////////////////////////////////////// | |||||
const RuntimeCheck ThreadingCheck14("ProductionGateway::ProductionGateway():ThreadingCheck14(0 == pthread_mutex_init(&MyMutex, NULL));"); | |||||
const RuntimeCheck ThreadingCheck15("ProductionGateway::ProductionGateway():ThreadingCheck15(0 == pthread_cond_init(&MyConditionVariable, NULL))"); | |||||
ProductionGateway::ProductionGateway() : // Construct in POSIX like this: | |||||
Product(0), // All of our counts start at zero. | |||||
Waiting(0), | |||||
Signaled(0) { | |||||
ThreadingCheck14(0 == pthread_mutex_init(&MyMutex, NULL)); // Initialize our mutex. | |||||
ThreadingCheck15(0 == pthread_cond_init(&MyConditionVariable, NULL)); // Initialize our condition variable. | |||||
} | |||||
const ExitCheck ThreadingCheck16("ProductionGateway::~ProductionGateway():ThreadingCheck16(0 == pthread_mutex_destroy(&MyMutex))"); | |||||
const ExitCheck ThreadingCheck17("ProductionGateway::~ProductionGateway():ThreadingCheck17(0 == pthread_cond_destroy(&MyConditionVariable))"); | |||||
ProductionGateway::~ProductionGateway() { // When we're done we must destroy | |||||
ThreadingCheck16(0 == pthread_mutex_destroy(&MyMutex)); // our local mutex and | |||||
ThreadingCheck17(0 == pthread_cond_destroy(&MyConditionVariable)); // our condition variable. | |||||
} | |||||
const RuntimeCheck ThreadingCheck18("ProductionGateway::produce():ThreadingCheck18(0 == pthread_mutex_lock(&MyMutex))"); | |||||
const RuntimeCheck ThreadingCheck19("ProductionGateway::produce():ThreadingCheck19(0 == pthread_cond_signal(&MyConditionVariable))"); | |||||
const RuntimeCheck ThreadingCheck20("ProductionGateway::produce():ThreadingCheck20(0 == pthread_mutex_unlock(&MyMutex))"); | |||||
void ProductionGateway::produce() { // To produce in POSIX | |||||
ThreadingCheck18(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. | |||||
++Product; // Add an item to our product count. | |||||
if(Signaled < Waiting) { // If anybody is waiting that has not | |||||
ThreadingCheck19(0 == pthread_cond_signal(&MyConditionVariable)); // yet been signaled then signal them | |||||
++Signaled; // and keep track. They will count this | |||||
} // down as they awaken. | |||||
ThreadingCheck20(0 == pthread_mutex_unlock(&MyMutex)); // At the end unlock our mutex so | |||||
} // waiting threads can fly free :-) | |||||
const RuntimeCheck ThreadingCheck21("ProductionGateway::consume():ThreadingCheck21(0 == pthread_mutex_lock(&MyMutex))"); | |||||
const RuntimeCheck ThreadingCheck22("ProductionGateway::consume():ThreadingCheck22(0 == pthread_cond_wait(&MyConditionVariable, &MyMutex))"); | |||||
const RuntimeCheck ThreadingCheck23("ProductionGateway::consume():ThreadingCheck23(0 == pthread_mutex_unlock(&MyMutex))"); | |||||
void ProductionGateway::consume() { // To consume in POSIX | |||||
ThreadingCheck21(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. | |||||
while(0 >= Product) { // Until we have something to consume, | |||||
++Waiting; // wait for a signal from | |||||
ThreadingCheck22(0 == pthread_cond_wait(&MyConditionVariable, &MyMutex)); // our producer. When we have a signal | |||||
--Waiting; // we are done waiting and we have | |||||
--Signaled; // been signaled. Of course, somebody | |||||
} // may have beaten us to it so check. | |||||
--Product; // If we have product then take it. | |||||
ThreadingCheck23(0 == pthread_mutex_unlock(&MyMutex)); // At the end unlock our mutex so | |||||
} | |||||
#endif | |||||
// End Production Gateway | |||||
//////////////////////////////////////////////////////////////////////////////// |
// threading.hpp | |||||
// | |||||
// (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
// The "Threading" module is a basic, cross-platform, multi-threading tool kit. | |||||
// The differences between posix compatible systems and win32 based systems are | |||||
// abstracted. On win32 systems, native win32 primatives are used to construct. | |||||
// efficient, lightweight objects. | |||||
// On others we assume we can use pthreads. In either case the objects we have | |||||
// here are designed to cover all of the basics efficiently while hiding the | |||||
// required under-cover work. | |||||
// A lot of this module is coded here in the header with the inline keyword | |||||
// because it is likely that the more basic objects can be efficiently compiled | |||||
// as inline abstractions to native calls. Really basic systems won't need | |||||
// anything beyond what is in this file. | |||||
// 20070202.1601 _M Further research has suggested that using a Semaphore in | |||||
// WIN32 environments in place of a CRITICAL_SECTION may provide the best | |||||
// performance and stability on all platforms. Specifically, SMP platforms may | |||||
// race and waste resources with CRITICAL_SECTIONs and in those cases it is | |||||
// recommended that the CRITICAL_SECTIONs may be "throttled" using Semaphores | |||||
// to limit the number of threads that may contend for a critical section. It | |||||
// is also suggested that if the Semaphore has an initialization value of 1 | |||||
// the CRITICAL_SECTION is redundant. So this code has been modified to do | |||||
// precisely that! | |||||
// | |||||
// This new version also includes a ProductionGateway object that simplifies | |||||
// the producer/consumer model. The object keeps track of the number of calls | |||||
// to produce() and consume() and ensures that threads will block on consume() | |||||
// until a sufficient number of calls to produce() are made. That is, for every | |||||
// one call to produce(), a call to consume() will be allowed to proceed. The | |||||
// object also allows for the potentially asynchronous nature of these calls. | |||||
// 20070530.1751 _M Added top level exception handling in threads along with | |||||
// isRunning() and isBad() methods. | |||||
// 20060528.1647 _M All of the basics are complete and tested on both WIN32 and | |||||
// RHEL4 single and multiple processors. | |||||
// Include MNR_threading Once Only ============================================= | |||||
#ifndef MNR_threading | |||||
#define MNR_threading | |||||
#include <set> | |||||
#include <vector> | |||||
#include <string> | |||||
#include <queue> | |||||
#include "faults.hpp" | |||||
using namespace std; | |||||
class ThreadManager; // ThreadManager does exist. | |||||
extern ThreadManager Threads; // Master thread manager. | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Thread Status & Type | |||||
// | |||||
// ThreadState objects are constant static objects defined for each Thread class | |||||
// so that the thread can update it's state by changing a pointer. The state | |||||
// can then be compared between threads of the same type and can be read-out | |||||
// as text for debugging purposes. | |||||
class ThreadState { // Thread State Object. | |||||
public: | |||||
const string Name; // Text name of thread descriptor. | |||||
ThreadState(string N) : Name(N) {} // Constructor requires text name. | |||||
}; | |||||
// ThreadType objects are constant static objects defined for each Thread class | |||||
// so that classes can be identified by type using a pointer to the constant. | |||||
class ThreadType { | |||||
public: | |||||
const string Name; | |||||
ThreadType(string N) : Name(N) {} | |||||
}; | |||||
class Thread; // There is such thing as a Thread. | |||||
class ThreadStatusRecord { // Describes a Thread's condition. | |||||
private: | |||||
Thread* Pointer; // A pointer to the thread. | |||||
ThreadType* Type; // A descriptor of it's type. | |||||
ThreadState* State; // A descriptor of it's state. | |||||
string Name; // Name of the thread if any. | |||||
bool isRunning; // True if the thread is running. | |||||
bool isBad; // True if the thread is bad. | |||||
string Fault; // Bad Thread's Fault if any. | |||||
public: | |||||
ThreadStatusRecord( // Initialize all items. | |||||
Thread* P, | |||||
ThreadType& T, | |||||
ThreadState& S, | |||||
bool R, | |||||
bool B, | |||||
string F, | |||||
string N | |||||
) : | |||||
Pointer(P), | |||||
Type(&T), | |||||
State(&S), | |||||
Name(N), | |||||
isRunning(R), | |||||
isBad(B), | |||||
Fault(F) | |||||
{} | |||||
ThreadStatusRecord& operator=(const ThreadStatusRecord& Right) { // Minimal Assignment Operator | |||||
Pointer = Right.Pointer; | |||||
Type = Right.Type; | |||||
State = Right.State; | |||||
isRunning = Right.isRunning; | |||||
isBad = Right.isBad; | |||||
Fault = Right.Fault; | |||||
Name = Right.Name; | |||||
return *this; | |||||
} | |||||
bool operator<(const ThreadStatusRecord& Right) { // Minimal Comparison Operator. | |||||
return (Pointer < Right.Pointer); | |||||
} | |||||
// How to get the details of the report. | |||||
const Thread* getPointer() { return Pointer; } | |||||
const ThreadType& getType() { return *Type; } | |||||
const ThreadState& getState() { return *State; } | |||||
bool getRunning() { return isRunning; } | |||||
bool getBad() { return isBad; } | |||||
string getFault() { return Fault; } | |||||
string getName() { return Name; } | |||||
}; | |||||
typedef vector<ThreadStatusRecord> ThreadStatusReport; // Status report type. | |||||
// End ThreadDescriptor | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// Win32 / POSIX abstractions | |||||
#ifdef WIN32 | |||||
// When in WIN32 land... | |||||
// Remember to compile (on GNU anyway) with -mthreads | |||||
#include <windows.h> | |||||
#include <process.h> | |||||
typedef HANDLE thread_primative; // The WIN32 thread primative abstracts | |||||
// HANDLE | |||||
typedef HANDLE mutex_primative; // The WIN32 mutex primative abstracts | |||||
// a HANDLE to a Semaphore. | |||||
inline void threading_yield() { // When we want to yield time in WIN32 | |||||
SwitchToThread(); // we call SwitchToThread(); | |||||
} | |||||
#else | |||||
// When in POSIX land... | |||||
// Remember to compile (on GMU anyway) with -pthread | |||||
#include <pthread.h> | |||||
#include <sched.h> | |||||
typedef pthread_t thread_primative; // The POSIX thread primative abstracts | |||||
// pthread_t | |||||
typedef pthread_mutex_t mutex_primative; // The POSIX mutex primative abstracts | |||||
// pthread_mutex_t | |||||
inline void threading_yield() { // When we want to yield time in POSIX | |||||
sched_yield(); // we call sched_yield(); | |||||
} | |||||
#endif | |||||
// End Win32 / POSIX abstractions | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// The Thread class gets extended to do any specific work. The pure virtual | |||||
// function MyTask is overloaded by the derived class to define that work. It | |||||
// is expected that the class will be initialized with any parameters that | |||||
// will be used by the thread and that the thread will make available any | |||||
// results through public interfaces either during and/or after the thread | |||||
// has finished running. | |||||
class Thread { | |||||
private: | |||||
ThreadState* MyThreadState; // Track current thread state. | |||||
protected: | |||||
const ThreadType& MyThreadType; // Identify thread type. | |||||
const string MyThreadName; // Name string of this instance. | |||||
thread_primative MyThread; // Abstracted thread. | |||||
bool RunningFlag; // True when thread is in myTask() | |||||
bool BadFlag; // True when myTask() throws! | |||||
string BadWhat; // Bad exception what() if any. | |||||
void CurrentThreadState(const ThreadState& TS); // Set thread state. | |||||
public: | |||||
Thread(); // Constructor (just in case) | |||||
Thread(const ThreadType& T, string N); // Construct with specific Type/Name | |||||
virtual ~Thread(); // Destructor (just in case) | |||||
void run(); // Method to launch this thread. | |||||
void join(); // Method to Join this thread. | |||||
void launchTask(); // Launch and watch myTask(). | |||||
virtual void myTask() = 0; // The actual task must be overloaded. | |||||
thread_primative getMyThread(); // Inspect my thread primative. | |||||
bool isRunning(); // Return the Running flag state. | |||||
bool isBad(); // Return the Bad flag state. | |||||
const string MyFault(); // Return exception Bad fault if any. | |||||
const string MyName(); // The thread's name. | |||||
const ThreadType& MyType(); // Thread type for this thread. | |||||
const ThreadState& MyState(); // Returns the current thread state. | |||||
const ThreadState& CurrentThreadState(); // Returns the current thread state. | |||||
ThreadStatusRecord StatusReport(); // Return's the thread's status reprt. | |||||
// Constants for Thread... | |||||
const static ThreadType Type; // The thread's type. | |||||
const static ThreadState ThreadInitialized; // Constructed successfully. | |||||
const static ThreadState ThreadStarted; // Started. | |||||
const static ThreadState ThreadFailed; // Failed by unhandled exception. | |||||
const static ThreadState ThreadStopped; // Stopped normally. | |||||
const static ThreadState ThreadDestroyed; // Safety value for destructed Threads. | |||||
}; | |||||
// End Thread | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// The Mutex class abstracts a lightweight, very basic mutex object. | |||||
// As with the Thread object, more ellaborate forms can be built up from | |||||
// this basic mechanism. An important design constraint for this basic | |||||
// mutex object is that it work even if the thread that's running was not | |||||
// created with the Thread object... that ensures that it can be used in | |||||
// code that is destined to function in other applications. | |||||
class Mutex { | |||||
private: | |||||
mutex_primative MyMutex; // Here is our primative mutex. | |||||
volatile bool IAmLocked; // Here is our Lock Count. | |||||
public: | |||||
Mutex(); // Construct the mutex. | |||||
~Mutex(); // Destroy the mutex. | |||||
void lock(); // Lock it. | |||||
void unlock(); // Unlock it. | |||||
bool tryLock(); // Try to lock it. | |||||
bool isLocked(); // Check to see if it's locked. | |||||
}; | |||||
// End of Mutex | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// ScopeMutex | |||||
// A ScopeMutex is a nifty trick for locking a mutex during some segment of | |||||
// code. On construction, it locks the Mutex that it is given and keeps it | |||||
// locked until it is destroyed. Of course this also means that it will unlock | |||||
// the mutex when it goes out of scope - which is precisely the point :-) | |||||
// | |||||
// The right way to use a ScopeMutex is to create it just before you need to | |||||
// have control and then forget about it. From a design perspective, you might | |||||
// want to make sure that whatever happens after the ScopeMutex has been | |||||
// created is as short as possible and if it is not then you may want to | |||||
// use the Mutex directly. | |||||
// | |||||
// The best place to use a ScopeMutex is where you might leave the controling | |||||
// bit of code through a number of logical paths such as a logic tree or even | |||||
// due to some exceptions. In this context it saves you having to track down | |||||
// all of the possible cases and unlock the mutex in each of them. | |||||
class ScopeMutex { | |||||
private: | |||||
Mutex& MyMutex; // ScopeMutex has an ordinary Mutex to use. | |||||
public: | |||||
ScopeMutex(Mutex& M); // Constructing a ScopeMutex requires a Mutex | |||||
~ScopeMutex(); // We do have special code for descrution. | |||||
}; | |||||
// End ScopeMutex | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// ProductionGateway | |||||
// A ProductionGateway encapsulates the thread synchronization required for a | |||||
// producer / consumer relationship. For each call to the produce() method one | |||||
// call to the consume() method can proceed. The object takes into account that | |||||
// these methods may be called out of sequence and that, for example, produce() | |||||
// might be called several times before any calls to consume. | |||||
#ifdef WIN32 | |||||
// Win32 Implementation //////////////////////////////////////////////////////// | |||||
class ProductionGateway { | |||||
private: | |||||
HANDLE MySemaphore; // WIN32 makes this one easy w/ a 0 semi. | |||||
public: | |||||
ProductionGateway(); // The constructor and destructor handle | |||||
~ProductionGateway(); // creating and destroying the semi. | |||||
void produce(); // Produce "releases" the semi. | |||||
void consume(); // Consume "waits" if needed. | |||||
}; | |||||
#else | |||||
// POSIX Implementation //////////////////////////////////////////////////////// | |||||
class ProductionGateway { // Posix needs a few pieces for this. | |||||
private: | |||||
mutex_primative MyMutex; // Mutex to protect the data. | |||||
pthread_cond_t MyConditionVariable; // A condition variable for signaling. | |||||
int Product; // A count of unused calls to produce() | |||||
int Waiting; // A count of waiting threads. | |||||
int Signaled; // A count of signaled threads. | |||||
public: | |||||
ProductionGateway(); // The constructor and destructor handle | |||||
~ProductionGateway(); // creating and destroying the semi. | |||||
void produce(); // Produce "releases" the semi. | |||||
void consume(); // Consume "waits" if needed. | |||||
}; | |||||
#endif | |||||
// End ProductionGateway | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// The ThreadManager class provides a global thread management tool. All Thread | |||||
// objects register themselves with the Threads object upon construction and | |||||
// remove themselves from the registry upon destruction. The Threads object can | |||||
// produce a status report for all of the known threads on the system and can | |||||
// temporarily lock the existing thread so that it can be contacted reliably. | |||||
// locking and unlocking the ThreadManager is intended only for short messages | |||||
// that set flags in the thread or pass some small data packet. The lock only | |||||
// prevents the thread from being destroyed before the message can be sent so | |||||
// that the thread that owns the threadlock will not make any calls to a dead | |||||
// pointer. Most apps should be designed so that the threadlock mechanism is | |||||
// not required. | |||||
class ThreadManager { // Central manager for threads. | |||||
friend class Thread; // Threads are friends. | |||||
private: | |||||
Mutex MyMutex; // Protect our data with this. | |||||
set<Thread*> KnownThreads; // Keep track of all threads. | |||||
void rememberThread(Thread* T); // Threads register themselves. | |||||
void forgetThread(Thread* T); // Threads remove themselves. | |||||
Thread* LockedThread; // Pointer to locked thread if any. | |||||
public: | |||||
ThreadManager():LockedThread(0){} // Initialize nice and clean. | |||||
ThreadStatusReport StatusReport(); // Get a status report. | |||||
bool lockExistingThread(Thread* T); // Locks ThreadManager if T exists. | |||||
void unlockExistingThread(Thread* T); // Unlocks ThreadManager if T locked. | |||||
}; | |||||
class ScopeThreadLock { // This is like a ScopeMutex for | |||||
private: // the ThreadManager. | |||||
Thread* MyLockedThread; // It needs to know it's Thread. | |||||
public: | |||||
ScopeThreadLock(Thread* T); // Locks T in ThreadManager if it can. | |||||
~ScopeThreadLock(); // Unlocks T in ThreadManager if locked. | |||||
bool isGood(); // True if T was locked. | |||||
bool isBad(); // False if T was not locked. | |||||
}; | |||||
// End Thread Manager | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// 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. | |||||
template<typename T> // Templatized | |||||
class ProductionQueue { // Production Queue Class | |||||
private: | |||||
Mutex myMutex; // Contains a mutex and | |||||
volatile unsigned 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. | |||||
unsigned int size() { // To check the size we look at | |||||
return LatestSize; // the blinking light. | |||||
} | |||||
}; | |||||
// End Production Queue | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
#endif | |||||
// End Of Include MNR_threading Once Only ====================================== |
// timing.cpp | |||||
// | |||||
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
// | |||||
// See the corresponding .hpp file for descriptions and history. | |||||
// | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
#include <ctime> | |||||
#include <sys/time.h> | |||||
#include <cerrno> | |||||
// Platform Specific Includes ////////////////////////////////////////////////// | |||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | |||||
#include <windows.h> | |||||
#endif | |||||
#include "timing.hpp" | |||||
// Introduce the standard namespace //////////////////////////////////////////// | |||||
using namespace std; | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class Sleeper - An object that remembers how long it is supposed to sleep. | |||||
// This allows an application to create "standard" sleep timers. This also | |||||
// helps keep sleeper values within range to avoid weird timing problems. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// Abstracted doRawSleep() function //////////////////////////////////////////// | |||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | |||||
// In a WIN32 environment Sleep() is defined and it works in milliseconds so | |||||
// we will use that for doRawSleep(). It's important to note that under normal | |||||
// circumstances win32 Sleep() may be off by quite a bit (15ms or so) due to | |||||
// how timing is done in the OS. There are ways around this, but they are | |||||
// sometimes complex - so here I've left things basic. If more precise win32 | |||||
// timing is needed then this method can be recoded using a workaround that is | |||||
// appropriate to the application. | |||||
void Sleeper::doRawSleep(int x) { | |||||
Sleep(x); // Use windows Sleep() | |||||
} | |||||
#else | |||||
// If we are not in a win32 environment then we're likely on a posix/unix system | |||||
// or at least we have the standard posix/unix time functions so we'll redefine | |||||
// absSleep to use nanosleep(); | |||||
void Sleeper::doRawSleep(int x) { | |||||
struct timespec sleeptime; // How much sleeping to do. | |||||
struct timespec remaining; // How much sleeping remains. | |||||
int result; // The latest result. | |||||
remaining.tv_sec = x/1000; // Divide ms by 1000 to get secs. | |||||
remaining.tv_nsec = (x%1000)*1000000; // Multiply the remaining msecs to get nsecs. | |||||
do { // Just in case we get interruped... | |||||
sleeptime.tv_sec = remaining.tv_sec; // Get our sleep time from the | |||||
sleeptime.tv_nsec = remaining.tv_nsec; // remaining time. | |||||
result = nanosleep(&sleeptime,&remaining); // Call nanosleep and get the remaining time. | |||||
} while(0>result && EINTR==errno); // If we were interrupted sleep some more. | |||||
} | |||||
#endif | |||||
Sleeper::Sleeper() // Constructed empty we set our | |||||
:MillisecondsToSleep(0) { // sleep time to zero. | |||||
} | |||||
Sleeper::Sleeper(int x) { // Constructed with a value we | |||||
setMillisecondsToSleep(x); // set the sleep time or throw. | |||||
} | |||||
int Sleeper::setMillisecondsToSleep(int x) { // Safe way to set the vlaue. | |||||
if(x < MinimumSleeperTime || | |||||
x > MaximumSleeperTime) // If it's not a good time value | |||||
throw BadSleeperValue(); // then throw the exception. | |||||
MillisecondsToSleep = x; // If it is good - set it. | |||||
return MillisecondsToSleep; // Return the set value. | |||||
} | |||||
int Sleeper::getMillisecondsToSleep() { // Safe way to get the value. | |||||
return MillisecondsToSleep; // Send back the value. | |||||
} | |||||
void Sleeper::sleep() { // Here's where we snooze. | |||||
if(MillisecondsToSleep > 0) { // If we have a good snooze | |||||
doRawSleep(MillisecondsToSleep); // value then go to Sleep(). | |||||
} else { // If the value is not good | |||||
throw BadSleeperValue(); // throw an exception. | |||||
} | |||||
} | |||||
void Sleeper::sleep(int x) { // Reset the sleep time then sleep. | |||||
setMillisecondsToSleep(x); // Set the sleep time. | |||||
sleep(); // Sleep. | |||||
} | |||||
void Sleeper::operator()() { // Syntactic sugar - operator() on | |||||
sleep(); // a sleeper calls sleep(). | |||||
} | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class PollTimer - An object to pause during polling processes where the | |||||
// time between polls is expanded according to a Fibonacci sequence. This | |||||
// allows self organizing automata to relax a bit when a particular process | |||||
// is taking a long time so that the resources used in the polling process are | |||||
// reduced if the system is under load - The idea is to prevent the polling | |||||
// process from loading the system when there are many nodes poling, yet to | |||||
// allow for a rapid response when there are few or when the answer we're | |||||
// waiting for is ready quickly. We use a Fibonacci expansion because it is | |||||
// a natural spiral. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
PollTimer::PollTimer(int Nom, int Max) : | |||||
NominalPollTime(MinimumSleeperTime), | |||||
MaximumPollTime(MinimumSleeperTime) { // Construction requires a | |||||
setNominalPollTime(Nom); // nominal delay to use and | |||||
setMaximumPollTime(Max); // a maximum delay to allow. | |||||
} | |||||
int PollTimer::setNominalPollTime(int Nom) { // Set the Nominal Poll Time. | |||||
if(Nom < MinimumSleeperTime || // Check the low and high | |||||
Nom > MaximumSleeperTime) // limits and throw an | |||||
throw BadPollTimerValue(); // exception if we need to. | |||||
// If the value is good then | |||||
NominalPollTime = Nom; // remember it. | |||||
if(MaximumPollTime < NominalPollTime) // Make sure the Maximum poll | |||||
MaximumPollTime = NominalPollTime; // time is >= the Nominal time. | |||||
reset(); // Reset due to the change. | |||||
return NominalPollTime; // Return the new value. | |||||
} | |||||
int PollTimer::setMaximumPollTime(int Max) { // Set the Maximum Poll Time. | |||||
if(Max < MinimumSleeperTime || // Check the low and high | |||||
Max > MaximumSleeperTime) // limits and throw an | |||||
throw BadPollTimerValue(); // exception if we need to. | |||||
// If the value is good then | |||||
MaximumPollTime = Max; // remember it. | |||||
if(MaximumPollTime < NominalPollTime) // Make sure the Maximum poll | |||||
MaximumPollTime = NominalPollTime; // time is >= the Nominal time. | |||||
reset(); // Reset due to the change. | |||||
return MaximumPollTime; // Return the new value. | |||||
} | |||||
void PollTimer::reset() { // Reset the spiral. | |||||
FibA = NominalPollTime; // Assume our starting event. | |||||
FibB = 0; // Assume no other events. | |||||
LimitReached=false; // Reset our limit watcher. | |||||
} | |||||
int PollTimer::pause() { // Pause between polls. | |||||
int SleepThisTime = MaximumPollTime; // Assume we're at out limit for now. | |||||
if(LimitReached) { // If actually are at our limit then | |||||
mySleeper.sleep(SleepThisTime); // use the current value. | |||||
} else { // If we are still expanding then | |||||
SleepThisTime = FibA+FibB; // Calculate the time to use and | |||||
if(SleepThisTime >= MaximumPollTime) { // check it against the limit. If | |||||
SleepThisTime = MaximumPollTime; // we reached the limit, us that value | |||||
LimitReached = true; // and set the flag. | |||||
} else { // If we haven't reached the limit yet | |||||
FibB=FibA; // then shift our events and remember | |||||
FibA=SleepThisTime; // this one to build our spiral. | |||||
} | |||||
mySleeper.sleep(SleepThisTime); // Take a nap. | |||||
} // Then FIRE THE MISSILES! | |||||
return SleepThisTime; // Tell the caller how long we slept. | |||||
} | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class Timer - This one acts much like a stop watch with millisecond | |||||
// resolution. The time is based on wall-clock time using gettimeofday(). | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
#ifdef WIN32 | |||||
// Here is the win32 version of getLocalRawClock() | |||||
#define TimerIsUnixBased (false) | |||||
msclock Timer::getLocalRawClock() const { | |||||
FILETIME t; // We need a FILETIME structure. | |||||
msclock c; // We need a place to calculate our value. | |||||
GetSystemTimeAsFileTime(&t); // Grab the system time. | |||||
c = (unsigned long long int) t.dwHighDateTime << 32LL; // Put full seconds into the high order bits. | |||||
c |= t.dwLowDateTime; // Put 100ns ticks into the low order bits. | |||||
c /= 10000; // Divide 100ns ticks by 10K to get ms. | |||||
c -= EPOCH_DELTA_IN_MSEC; // Correct for the epoch difference. | |||||
return c; // Return the result. | |||||
} | |||||
#else | |||||
// Here is the unix/posix version of getLocalRawClock() | |||||
#define TimerIsUnixBased (true) | |||||
msclock Timer::getLocalRawClock() const { | |||||
struct timeval t; // We need a timval structure. | |||||
msclock c; // We need a place to calculate our value. | |||||
gettimeofday(&t,NULL); // Grab the system time. | |||||
c = t.tv_sec * 1000; // Put the full seconds in as milliseconds. | |||||
c += t.tv_usec / 1000; // Add the microseconds as milliseconds. | |||||
return c; // Return the milliseconds. | |||||
} | |||||
#endif | |||||
Timer::Timer() { // Construct by resetting the | |||||
start(); // clocks by using start(); | |||||
} | |||||
Timer::Timer(msclock startt): // Construct a timer from a specific time. | |||||
RunningFlag(true), // Set the running flag, | |||||
StartTime(startt), // the start time and | |||||
StopTime(startt) { // the stop time clock to startt. | |||||
} | |||||
void Timer::clear() { // Stop, zero elapsed, now. | |||||
StartTime = StopTime = getLocalRawClock(); // Set the start and stop time | |||||
RunningFlag = false; // to now. We are NOT running. | |||||
} | |||||
msclock Timer::start() { // (re) Start the timer at this moment. | |||||
return start(getLocalRawClock()); // start() using the current raw clock. | |||||
} | |||||
msclock Timer::start(msclock startt) { // (re) Start a timer at startt. | |||||
StartTime = StopTime = startt; // Set the start and end clocks. | |||||
RunningFlag = true; // Set the running flag to true. | |||||
return StartTime; // Return the start clock. | |||||
} | |||||
msclock Timer::getStartClock() { return StartTime; } // Return the start clock value. | |||||
bool Timer::isRunning() { return RunningFlag; } // Return the running state. | |||||
msclock Timer::getElapsedTime() const { // Return the elapsed timeofday - | |||||
msclock AssumedStopTime; // We need to use a StopTime simulation. | |||||
if(RunningFlag) { // If we are running we must get | |||||
AssumedStopTime = getLocalRawClock(); // the current time (as if it were stop). | |||||
} else { // If we are not running we use | |||||
AssumedStopTime = StopTime; // the actual stop time. | |||||
} | |||||
msclock delta = AssumedStopTime - StartTime; // Calculate the difference. | |||||
return delta; // That's our result. | |||||
} | |||||
msclock Timer::stop() { // Stop the timer. | |||||
StopTime = getLocalRawClock(); // Grab the time and then stop | |||||
RunningFlag=false; // the clock. | |||||
return StopTime; // Return the time we stopped. | |||||
} | |||||
msclock Timer::getStopClock() { return StopTime; } // Return the stop clock value. | |||||
double Timer::getElapsedSeconds() const { // Calculate the elapsed seconds. | |||||
msclock e = getElapsedTime(); // Get the elapsed time in msecs. | |||||
double secs = (double) e / 1000.0; // Calculate seconds from msecs. | |||||
return secs; | |||||
} | |||||
bool Timer::isUnixBased() { return TimerIsUnixBased; } // Is this timer unix based? | |||||
msclock Timer::toWindowsEpoch(msclock unixt) { // Convert a unix based msclock to win32 based. | |||||
return (unixt + EPOCH_DELTA_IN_MSEC); // Going this way we add the epoch delta. | |||||
} | |||||
msclock Timer::toUnixEpoch(msclock win32t) { // Convert a win32 based msclock to a unix based. | |||||
return (win32t - EPOCH_DELTA_IN_MSEC); // Going this way we subtract the epoch delta. | |||||
} | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class Timeout - This one uses a Timer to establish a timeout value. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
Timeout::Timeout(msclock duration):myDuration(duration) { } // Create, set the duration, start. | |||||
msclock Timeout::setDuration(msclock duration) { // Set/Change the duration in milliseconds. | |||||
myDuration = duration; // (re) Set the duration. | |||||
return myDuration; // Return the current (new) duration. | |||||
} | |||||
msclock Timeout::getDuration() { // Return the current duration. | |||||
return myDuration; | |||||
} | |||||
msclock Timeout::restart() { // Restart the timeout timer. | |||||
return myTimer.start(); // Restart the clock and return the time. | |||||
} | |||||
msclock Timeout::getElapsedTime() { // Get elapsed milliseconds. | |||||
return myTimer.getElapsedTime(); // Return the elapsed time. | |||||
} | |||||
msclock Timeout::getRemainingTime() { // Get remaining milliseconds. | |||||
msclock remaining = 0ULL; // Assume we're expired to start. | |||||
msclock elapsed = myTimer.getElapsedTime(); // Get the elapsed time. | |||||
if(elapsed < myDuration) { // If there is still time then | |||||
remaining = myDuration - elapsed; // calculate what is left. | |||||
} | |||||
return remaining; // Return what we found. | |||||
} | |||||
bool Timeout::isExpired() { // Return true if time is up. | |||||
return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration. | |||||
} |
// timing.hpp | |||||
// | |||||
// Copyright (C) 2004-2009 MicroNeil Research Corporation. | |||||
// This program is part of the MicroNeil Research Open Library Project. For | |||||
// more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
// | |||||
// This program is free software; you can redistribute it and/or modify it | |||||
// under the terms of the GNU General Public License as published by the | |||||
// Free Software Foundation; either version 2 of the License, or (at your | |||||
// option) any later version. | |||||
// | |||||
// This program is distributed in the hope that it will be useful, but WITHOUT | |||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
// more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License along with | |||||
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
// Place, Suite 330, Boston, MA 02111-1307 USA | |||||
// The purpose of this module is to abstract timing functions for | |||||
// cross platform C++ development usning GNU compilers in *nix and | |||||
// win32 environments (minGW). Timing resolution is in milliseconds | |||||
// throughout to provide consistency and reasonable expectations. | |||||
// 20060404 _M Added Timer::start(msclock startt) for chaining. | |||||
// 20060403 _M This "timing" module has been completed and tested on | |||||
// win32 (compiled using CodeBlocks and minGW) and on RHES3 (g++). | |||||
// | |||||
// The bottom line is that this code is perfect for most applications that | |||||
// don't need real-time interaction on the win32 platform. That is, for | |||||
// any application that can accept 15ms or so of "wiggle" in their timing | |||||
// functions. On linux I was able to observe very consistent results with | |||||
// variations measured in 1-2ms. | |||||
// | |||||
// Aynone seeking real-time accuracy on the win32 platform will need to contend | |||||
// with all of the landmines in place against that and will need to write more | |||||
// ellaborate versions of Timer::getLocalRawClock() and Sleeper::doRawSleep() | |||||
// aa appropriate for their application. The existing code should work fine for | |||||
// almost all other applications. | |||||
// | |||||
// This code was written with that in mind to some extent. That is why all of | |||||
// the timing functions are measured in milliseconds rather than microseconds | |||||
// or something smaller. Milliseconds are convenient for polling delays, | |||||
// communications timeouts, measuring database application performance, and | |||||
// other similar tasks. For that purpose - this timing module is just fine :-) | |||||
// 20060323 _M Rewrote this module from a combination of previous | |||||
// bits and pieces. This module will provide classes that abstract | |||||
// timing functions for use in GNU projects on *nix and win32 systems. | |||||
#ifndef MNR_timing | |||||
#define MNR_timing | |||||
// Introduce the standard namespace /////////////////////////////////////////// | |||||
using namespace std; | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class Sleeper - An object that remembers how long it is supposed to sleep. | |||||
// This allows an application to create "standard" sleep timers that can be | |||||
// established at the top of the code (easy to find) and reused. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
static const int MinimumSleeperTime = 1; // Minimum msec allowed. | |||||
static const int MaximumSleeperTime = 2000000000; // Maximum msec allowed. | |||||
class Sleeper { | |||||
private: | |||||
int MillisecondsToSleep; // How long to sleep. | |||||
void doRawSleep(int x); // Abstracted local sleep function. | |||||
public: | |||||
class BadSleeperValue {}; // Exception for bad values. | |||||
Sleeper(); // Constructed empty - set to zero. | |||||
Sleeper(int x); // Constructed with a value. | |||||
int setMillisecondsToSleep(int x); // Safe way to set the vlaue. | |||||
int getMillisecondsToSleep(); // Safe way to get the value. | |||||
void sleep(); // Here's where we snooze if we can. | |||||
void sleep(int x); // Shortcut - set the time and then sleep. | |||||
void operator()(); | |||||
}; | |||||
/* Sleeper Documentation... | |||||
** | |||||
** Sleeper.Sleeper() | |||||
** Constructs a Sleeper with a zero value. | |||||
** | |||||
** Sleeper.Sleeper(int x) | |||||
** Constructs a Sleeper to "snooze" for x milliseconds. | |||||
** | |||||
** Sleeper.setMillisecondsToSleep(int x) | |||||
** Sets the sleep time for the Sleeper and returns the time set. | |||||
** If the value is out of range then the Sleeper::BadSleeperValue will be thrown. | |||||
** | |||||
** Sleeper.getMillisecondsToSleep() | |||||
** Returns the current MillisecondsToSleep. | |||||
** | |||||
** Sleeper.sleep() | |||||
** Goes to sleep for MillisecondsToSleep. If MillisecondsToSleep has not been set | |||||
** then the function throws Sleeper::BadSleeperVlaue. | |||||
** | |||||
** Sleeper.sleep(int x) | |||||
** First sets MillisecondsToSleep, then goes to sleep. If x is too big or too small | |||||
** then the method throws Sleeper::BadSleeperValue. | |||||
*/ | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class PollTimer - An object to pause during polling processes where the | |||||
// time between polls is expanded according to a Fibonacci sequence. This | |||||
// allows self organizing automata to relax a bit when a particular process | |||||
// is taking a long time so that the resources used in the polling process are | |||||
// reduced if the system is under load - The idea is to prevent the polling | |||||
// process from loading the system when there are many nodes poling, yet to | |||||
// allow for a rapid response when there are few or when the answer we're | |||||
// waiting for is ready quickly. We use a Fibonacci expansion because it is | |||||
// a natural spiral. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
class PollTimer { | |||||
private: | |||||
Sleeper mySleeper; // We need a sleeper to do this. | |||||
int NominalPollTime; // Normal poll delay in msec. | |||||
int MaximumPollTime; // Maximum poll delay in msec. | |||||
bool LimitReached; | |||||
// Why not use unsigned int everywhere? Because sometimes libraries use | |||||
// int for their Sleep() functions... so we calculate with unsigned ints, | |||||
// but we use ints for inputs to keep things sane. Wierd bugs show up if | |||||
// signed ints overflow in clock_t values -- this learned by experience. | |||||
unsigned int FibA; // One poll delay ago. | |||||
unsigned int FibB; // Two poll delays ago. | |||||
// FibA and FibB are used to generate the fibonacci expansion. The current | |||||
// delay will always be the sum of the previous two delays assuming that | |||||
// there was always a first delay of 1 x Nominal Poll time. This results | |||||
// in an expansion like this: 1,2,3,5,8,13,21,34,... | |||||
public: | |||||
class BadPollTimerValue {}; // Exception for bad values. | |||||
PollTimer(int Nom, int Max); // Construct with nominal and max delays. | |||||
int setNominalPollTime(int Nom); // Set the Nominal Poll Time. | |||||
int setMaximumPollTime(int Max); // Set the Maximum Poll Time. | |||||
void reset(); // Reset the spiral. | |||||
int pause(); // Pause between polls. | |||||
}; | |||||
/* PollTimer Documentation... | |||||
** | |||||
** PollTimer(nominal_delay, maximum_delay) | |||||
** Constructs a PollTimer and sets it's basic parameters. If the parameters are | |||||
** out of range then BadPollTimerValue will be thrown. | |||||
** | |||||
** setNiminalPollTime(Nom) | |||||
** Sets the nominal (base unit) poll delay time. Throws BadPollTimerValue if | |||||
** the value is out of range. | |||||
** | |||||
** setMaximumPollTime(Max) | |||||
** Sets the maximum (upper limit) poll delay. If the value is out of range then | |||||
** BadPollTimerValue is thrown. | |||||
** | |||||
** reset() | |||||
** Resets the current poll delay to the nominal delay. The next call to pause() | |||||
** will sleep for the nominal delay. This method would normally be called when | |||||
** a poll cycle turns up some work to do so that subsequent poll delays will be | |||||
** short - leading to a responsive system. | |||||
** | |||||
** pause() | |||||
** Calling this method will cause the current thread to sleep for the current | |||||
** poll delay time. Subsquent calls to pause will cause longer sleep times | |||||
** according to a natural spiral. An intervening call to reset() will shorten | |||||
** the delay times again. This method returns the number of milliseconds | |||||
** paused on this pass. | |||||
*/ | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class Timer - This one acts much like a stop watch with millisecond | |||||
// resolution. The time is based on wall-clock time using gettimeofday() or | |||||
// GetSystemTimeAsFileTime depending on the OS. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
typedef unsigned long long int msclock; // 64 bit int used for measuring time in ms. | |||||
static msclock EPOCH_DELTA_IN_USEC = 11644473600000000ULL; // Microseconds difference between epochs. | |||||
static msclock EPOCH_DELTA_IN_MSEC = EPOCH_DELTA_IN_USEC / 1000; // Milliseconds difference between epochs. | |||||
class Timer { | |||||
private: | |||||
bool RunningFlag; // True if clock is running. | |||||
msclock StartTime; // TimeOfDay at start. | |||||
msclock StopTime; // TimeOfDay at stop or check. | |||||
msclock getLocalRawClock() const; // Derives unix epoch ms from local clock. | |||||
public: | |||||
Timer(); // Construct and start the Timer. | |||||
Timer(msclock startt); // Constructs and starts from a specific moment. | |||||
void clear(); // Stop and set elapsed time to zero at now. | |||||
msclock start(); // Re(set) the Start time to this moment. | |||||
msclock start(msclock startt); // Re(set) the Start time to startt. | |||||
msclock getStartClock(); // Return the unix epoch start clock. | |||||
bool isRunning(); // Return true if the clock is running. | |||||
msclock getElapsedTime() const; // get milliseconds since Timer start. | |||||
msclock stop(); // Stop the Timer. | |||||
msclock getStopClock(); // Return the unix epoch stop clock. | |||||
double getElapsedSeconds()const; // Get floating point elapsed seconds. | |||||
bool isUnixBased(); // True if base clock is unix/posix. | |||||
msclock toWindowsEpoch(msclock unixt); // Converts unix t to windows t. | |||||
msclock toUnixEpoch(msclock win32t); // Converts windows t to unix t. | |||||
}; | |||||
/* Timer Documentation... | |||||
** | |||||
** All raw clock values are returned as 64 bit unsigned integers using a special | |||||
** type - msclock. Conversions are done using microsecond accuracy. | |||||
** | |||||
** Timer() | |||||
** Creates a new timer and starts the clock at this moment. | |||||
** | |||||
** Timer(msclock startt) | |||||
** Creates a new timer and starts the clock at a specific moment. This can be | |||||
** used to start one clock precisely when another one ends as in: | |||||
** new Timer B(A.stop()); | |||||
** | |||||
** getLocalRawClock() | |||||
** This method uses slightly different code depending upon whether the system | |||||
** is a unix box or win32. In both cases the function determines the local time | |||||
** value as a 64bit integer with millisecond resolution using the unix epoch of | |||||
** Jan 1, 1970. | |||||
** | |||||
** start() | |||||
** This method starts or restarts the Timer's clock at this moment. | |||||
** The msclock value for the start clock is returned. | |||||
** | |||||
** start(msclock startt) | |||||
** This method starts or restarts the Timer's clock at the time specified | |||||
** int startt. This is used for chaining operations such as B.start(A.stop()) | |||||
** | |||||
** getStartClock() | |||||
** This method returns the start clock value. | |||||
** | |||||
** isRunning() | |||||
** Returns true if the clock is running. | |||||
** | |||||
** getElapsedTime() | |||||
** This method returns the elapsed time in milliseconds. | |||||
** If the clock is running this value will be different each time it is called. | |||||
** | |||||
** stop() | |||||
** This method stops the clock and returns the stop clock value. If this method | |||||
** is called more than once then the stop clock is reset to the current time and | |||||
** that time is returned. | |||||
** | |||||
** getStopClock() | |||||
** This method returns the stop clock value. If the Timer is still running | |||||
** then the result is the same as calling getElapsedTime(). If the clock is | |||||
** not running then the time the clock was last stopped is returned. | |||||
** | |||||
** getElapsedSeconds() | |||||
** Returns the elapsed time as a floating point number with millisecond | |||||
** resolution. | |||||
** | |||||
** isUnixBased() | |||||
** Returns true if the raw clock values are being derived from a unix/posix OS. | |||||
** | |||||
** toWindowsEpoch(msclock unixt) | |||||
** Converts unixt to a windows value by adding the epoch delta. | |||||
** | |||||
** toUnixEpoch(msclock win32t) | |||||
** Converts win32t to a unix value by subtracting the epoch delta. | |||||
*/ | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
// class ScopeTimer - Runs a Timer while ScopeTimer is in scope. | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
class ScopeTimer { // Runs a timer when in scope. | |||||
private: | |||||
Timer& myTimer; // This is the timer to run. | |||||
public: | |||||
ScopeTimer(Timer& T) : myTimer(T) { myTimer.start(); } // The Timer starts at construction. | |||||
~ScopeTimer() { myTimer.stop(); } // The Timer stops at destruction. | |||||
}; | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
// class Timeout - This one uses a Timer to establish a timeout value. | |||||
/////////////////////////////////////////////////////////////////////////////// | |||||
class Timeout { | |||||
private: | |||||
Timer myTimer; // We need a timer to do this. | |||||
msclock myDuration; // Milliseconds before timout expires. | |||||
public: | |||||
class BadTimeoutValue {}; // If the value is bad throw this. | |||||
Timeout(msclock duration); // Create and set the duration. | |||||
msclock setDuration(msclock duration); // Set/Change the duration in milliseconds. | |||||
msclock getDuration(); // Return the current duration in milliseconds. | |||||
msclock restart(); // Restart the timeout timer. | |||||
msclock getElapsedTime(); // Get elapsed milliseconds. | |||||
msclock getRemainingTime(); // Get remaining milliseconds. | |||||
bool isExpired(); // Return true if time is up. | |||||
}; | |||||
/* Timeout Documentation... | |||||
** | |||||
** Timeout(int duration) | |||||
** Creates a Timout timer and sets the duration in milliseconds. | |||||
** | |||||
** setDuration(int duration) | |||||
** Sets or changes the duration of the timeout timer. | |||||
** The Timout is NOT reset by this method. This allows you to change | |||||
** the timeout on the fly. | |||||
** | |||||
** restart() | |||||
** Restarts the timeout timer. | |||||
** | |||||
** getElapsedTime() | |||||
** Returns the number of milliseconds elapsed since the Timout was created | |||||
** or reset. | |||||
** | |||||
** getRemainingTime() | |||||
** Returns the number of milliseconds remaining before time is up. | |||||
** | |||||
** isExpired() | |||||
** Returns true if time is up. | |||||
*/ | |||||
#endif // End MNR_timing once-only switch. |
# List of IPs to Ignore on startup | |||||
# Each IP in this list is set to Ignore in GBUdb when | |||||
# The configuration is loaded. | |||||
# Hash mark on the beginning of a line indicates a comment. | |||||
# Comments after an IP are also ignored. | |||||
# One line per IP. Sorry, no CIDR yet. | |||||
# Be sure to list ALL of your gateways :-) | |||||
127.0.0.1 # ignore localhost, of course. |
<!-- Copyright 2009, ARM Research Labs, LLC --> | |||||
<html> | |||||
<body> | |||||
<font face="sans-serif"> | |||||
<h1>Message Sniffer SDK for Win* V3.1</h1> | |||||
<h2>Contents</h2> | |||||
</font><h3><ol> | |||||
<p><font face="sans-serif">Introduction</font></p> | |||||
<li><font face="sans-serif"><a href="#Begin">Before you begin!</a></font></li> | |||||
<li><font face="sans-serif"><a href="#Contents">Contents of the SDK</a></font></li> | |||||
<li><font face="sans-serif"><a href="#Description">SNFMulti DLL Description</a></font></li> | |||||
<li><font face="sans-serif"><a href="ChangeLog.txt">Change Log</a></font></li> | |||||
<p><font face="sans-serif">Setup notes and important instructions</font></p> | |||||
<li><font face="sans-serif"><a href="SNFServer_readme.txt">SNFServer Setup Readme</a></font></li> | |||||
<li><font face="sans-serif"><a href="SNFClient_readme.txt">SNFClient Setup Readme</a></font></li> | |||||
<p><font face="sans-serif">Code Samples</font></p> | |||||
<li><font face="sans-serif"><a href="32bitDll/snfmultidll.h">C Header File (snfmultidll.h></a></font></li> | |||||
<li><font face="sans-serif"><a href="32bitDll/libsnfmulti.def">Module Definition File (libsnfmulti.def)</a></font></li> | |||||
<li><font face="sans-serif"><a href="C++/main.cpp">C++ Sample Code</a></font></li> | |||||
<li><font face="sans-serif"><a href="VB/SNFMulti_in_VB.Net.txt">VB.Net Sample Code</a></font></li> | |||||
<p><font face="sans-serif">API Reference - Functions listed in the order they should be used</font></p> | |||||
<li><font face="sans-serif"><a href="#startupSNF">startupSNF()</a> - Initializes the SNF engine and loads the rule base</font></li> | |||||
<li><font face="sans-serif"><a href="#startupSNFAuthenticated">startupSNFAuthenticated()</a> - Initializes SNF with license info</font></li> | |||||
<li><font face="sans-serif"><a href="#setThrottle">setThrottle()</a> - Sets a concurrent thread limit (if desired)</font></li> | |||||
<li><font face="sans-serif"><a href="#testIP">testIP()</a> - Returns the GBUdb reputation range for an IP</font></li> | |||||
<li><font face="sans-serif"><a href="#getIPReputation">getIPReputation()</a> - Returns IP Reputation Figure for an IP</font></li> | |||||
<li><font face="sans-serif"><a href="#scanBuffer">scanBuffer()</a> - Scans a message buffer</font></li> | |||||
<li><font face="sans-serif"><a href="#scanFile">scanFile()</a> - Scans a message file</font></li> | |||||
<li><font face="sans-serif"><a href="#getScanXHeaders">getScanXHeaders()</a> - Returns the scan result and XHeaders</font></li> | |||||
<li><font face="sans-serif"><a href="#getScanXMLLog">getScanXMLLog()</a> - Returns the scan result and XML Log data</font></li> | |||||
<li><font face="sans-serif"><a href="#getScanClassicLog">getScanClassicLog()</a> - Returns the scan result and Classic Log Data</font></li> | |||||
<li><font face="sans-serif"><a href="#getScanResult">getScanResult()</a> - Returns the scan result (nothing else)</font></li> | |||||
<li><font face="sans-serif"><a href="#closeScan">closeScan()</a> - Closes the scan and releases resources</font></li> | |||||
<li><font face="sans-serif"><a href="#shutdownSNF">shutdownSNF()</a> - Shuts down the SNF engine</font></li> | |||||
<p><font face="sans-serif">Miscellaneous</font></p> | |||||
<li><font face="sans-serif"><a href="#ResultCodes">Result Codes</a> - Error and Scan Result Mnemonics</font></li> | |||||
</ol></h3><font face="sans-serif"> | |||||
<hr/> | |||||
<a name="Begin"><h3>Before you begin!</h3></a> | |||||
<p>This SDK contains a complete Message Sniffer engine. You MUST be familiar with that engine | |||||
before you can effectively use this SDK. If you do not already have an OEM license or trial | |||||
SNF rule base license then please <a href="http://www.armresearch.com/">visit our web site first | |||||
and get one!</a> The engine won't run without it.</p> | |||||
<p>We highly recommend that you have some experience with our SNFServer and SNFClient applications | |||||
before you begin writing your own or begin integrating the SNF engine into your own software.</p> | |||||
<p>We're not saying it's hard to do -- quite the opposite actually, BUT SNF is a sophisticated | |||||
piece of software with a lot of capabilities and options. You will have much better results | |||||
if you are familiar with these before you begin ;-)</p> | |||||
<hr/> | |||||
<a name="Contents"><h3>Contents of the SDK</h3></a> | |||||
<p>This SDK contains the following: | |||||
<ol> | |||||
<li><font face="sans-serif">Documentation files, including | |||||
this file.</font></li> | |||||
<li><font face="sans-serif">DLLs (both 32 bit and 64 bit | |||||
versions) and the required header files (in | |||||
directory <b>include</b>).</font></li> | |||||
<li><font face="sans-serif">Sample programs in C++ (in | |||||
directory <b>CPPSample</b>), C# (<b>CSSample</b>), and Visual | |||||
Basic (<b>VBSample</b>).</font></li> | |||||
<li><font face="sans-serif">VS 2008 Solution files to build | |||||
the sample program in C++ (in | |||||
directory <b>VS2008CPPSample</b>), in C# | |||||
(<b>VS2008CSSample</b>), and Visual Basic | |||||
(<b>VS2008VBSample</b>).<br> | |||||
The <b>VS2008CPPSample\README</b> contains instructions for | |||||
creating the SNFMulti import libraries for use with VS 2008. | |||||
</font></li> | |||||
<li><font face="sans-serif">Other applications | |||||
(<b>curl</b>, <b>SNFClient</b>, and <b>getRulebase</b>) and | |||||
configuration files needed to support SNF | |||||
operation.</font></li> | |||||
</ol> | |||||
There are also directions for building VS 2008 import libraries in <b>VS2008CPPSample\README</b>. | |||||
</p> | |||||
<hr/> | |||||
<a name="Description"><h3>SNFMulti DLL Description</h3></a> | |||||
<p>The SNF SDK for Win* is based on a DLL. The DLLs for both the 32 bit | |||||
and 64 bit versions are included here. | |||||
</p> | |||||
<p>The DLL contains the entire SNFServer engine and provides a simple API for starting the | |||||
engine, scanning messages, and retrieving the results. Since the entire SNFServer engine is | |||||
included you also have the option of using the SNFClient utility once your application has | |||||
started the SNF engine. You can also make calls to the engine using the XCI protocol (which | |||||
is how SNFClient does it's work)</p> | |||||
<p>Of course the best way to use the DLL is to perform scans directly through the API. The | |||||
best performance can be achieved by scanning a message in memory via the scanBuffer() function | |||||
since this can be done at the full speed of the processor without waiting for IO operations.</p> | |||||
<p>The DLL is fully thread-safe so you can perform as many concurrent scans as you wish. Also, | |||||
just in case it will make things easier for you, the DLL provides a throttling function which | |||||
can limit the number of concurrent scans. (It won't unless you ask it to.)</p> | |||||
<p>The general form of an application using the DLL will first start the engine, then | |||||
optionally set the throttle, then perform scans (perform a scan, get results, close the scan, repeat), | |||||
and finally it will shutdown the engine.</p> | |||||
<p>Since the DLL contains the entire SNFServer engine, it can (and must) be configured in | |||||
exactly the same way as SNFServer. <a href="http://www.armresearch.com/support/articles/software/snfServer/config/index.jsp"> | |||||
Documentation for configuring SNFServer can be found on our web site.</a></p> | |||||
<p>New in snfmulti.dll V3.0!</p> | |||||
<p>OEM developers can now protect their licenseID and Authentication string by providing it directly to the SNF engine at run-time. When combined with an internal mechanism for downloading rule base files this makes it practical to control SNF license information entirely within the OEM's application. <a href="#startupSNFAuthenticated">See startupSNFAuthenticated() for details.</a></p> | |||||
<hr/> | |||||
<a name="startupSNF"><h3>int startupSNF(char* path);</h3></a> | |||||
<p>This function initializes the SNF scanning engine using the configuration file provided. | |||||
The configuration file identifies all of the operational parameters for the SNF engine including | |||||
the location of the working directories and rule base file, SNF license information, and | |||||
much more. <a href="http://www.armresearch.com/support/articles/software/snfServer/config/index.jsp"> | |||||
See our web site for details on configuring the SNF engine.</a></p> | |||||
<dl> | |||||
<dd><b>path</b> = The full path to the snf_engine.xml file as a null terminated string.</dd> | |||||
<dd><b>returns</b> snf_SUCCESS when successful, otherwise see <a href="#ResultCodes">Error Codes</a>.</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="startupSNFAuthenticated"><h3>int startupSNFAuthenticated(char* path, char* lic, char* auth);</h3></a> | |||||
<p>This function initializes the SNF scanning engine using the configuration file and authentication | |||||
information provided. When SNF is started with this function the identity.xml file can be omitted and | |||||
the identity= attribute of the <node/> element in snf_engine.xml can be omitted. This allows OEM | |||||
developers to protect their authentication string by retrieving it from an encrypted source at run-time | |||||
and providing it directly to the SNF engine.</p> | |||||
<p>In all other ways the SNF engine is configured in the same as when using <a href="#startupSNF">startupSNF() (see above)</a></p> | |||||
<p>Note that if you intend to use this mechanism to protect your SNF license information you will also need to | |||||
address the mechanism you use to download and verify rule base files. Either build a mechanism to download and | |||||
authenticate your rule base file without exposing your authentication string or you might modify the existing | |||||
getRulebase script to remove the snf2check operation and the associated authentication string. The SNF engine will | |||||
check all rule base files before they are loaded for scanning and will refuse to load a rule base file that does | |||||
not authenticate properly.</p> | |||||
<dl> | |||||
<dd><b>path</b> = The full path to the snf_engine.xml file as a null terminated string.</dd> | |||||
<dd><b>lic</b> = The 8 character license id as a null terminated string.</dd> | |||||
<dd><b>auth</b> = The 16 character authentication string as a null terminated string.</dd> | |||||
<dd><b>returns</b> snf_SUCCESS when successful, otherwise see <a href="#ResultCodes">Error Codes</a>.</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="setThrottle"><h3>int setThrottle(int Threads);</h3></a> | |||||
<p>This function establishes a limit on the number of concurrent scans that can run. Any additional | |||||
threads will block until at least one of the active scans is completed.</p> | |||||
<p>The default value for the throttle setting is zero. When the throttle is set to zero then no limits | |||||
are placed on the number of concurrent scans. In this mode the application must limit the number of | |||||
concurrent scans.</p> | |||||
<dl> | |||||
<dd><b>Threads</b> = The number of concurrent scans allowed.</dd> | |||||
<dd><b>returns</b> the number of Threads if successful otherwise snf_ERROR_EXCEPTION.</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="testIP"><h3>int testIP(unsigned long int IPToCheck);</h3></a> | |||||
<p>This function tests an IP against the GBUdb. This function returns very quickly and can be called | |||||
as often as required without any follow-up actions as long as the SNF Engine is active (between startupSNF() | |||||
and shutdownSNF()). This function is thread-safe and does not interfere with other scanning functions.</p> | |||||
<p>GBUdb gathers it's statistics based on the message scans that are performed. Information about those | |||||
scans is also shared with other SNF nodes approximately once every minute. No external queries are | |||||
performed to gather GBUdb data. As a result GBUdb can only provide an IP reputation for IPs that sourced | |||||
messages scanned by this SNF node.</p> | |||||
<p>Put another way - GBUdb does not work like a conventional real-time black list. Message scans must | |||||
be performed in order for GBUdb to provide IP reputation information.</p> | |||||
<p>For more information on how GBUdb works visit the | |||||
<a href="http://www.armresearch.com/support/articles/technology/GBUdb/index.jsp"> | |||||
GBUdb Technology section of our web site.</a></p> | |||||
<dl> | |||||
<dd><b>IPToCheck</b> = The IP to test.</dd> | |||||
<dd><b>returns</b> an integer representing the GBUdb Range associated with the IP if successful | |||||
otherwise snf_ERROR_EXCEPTION.</dd> | |||||
</dl> | |||||
<h4>GBUdb Range MNemonics from enum snfIPRange</h4> | |||||
<dl> | |||||
<dd>Unknown, snf_IP_Unknown = 0</dd> | |||||
<dd>White, snf_IP_White = 1</dd> | |||||
<dd>Normal, snf_IP_Normal = 2</dd> | |||||
<dd>New, snf_IP_New = 3</dd> | |||||
<dd>Caution, snf_IP_Caution = 4</dd> | |||||
<dd>Black, snf_IP_Black = 5</dd> | |||||
<dd>Truncate, snf_IP_Truncate = 6</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="getIPReputation"><h3>double getIPReputation(unsigned long int IPToCheck);</h3></a> | |||||
<p>This function returns a number representing the overall reputation of the IP based on local GBUdb statistics. | |||||
This number (Reputation Figure) can be easily manipulated to provide additional weight values in systems that combine | |||||
multiple tests using a weight based scoring system. The Reputation Figure is calculated by combining the Probability figure and the Confidence figure using the formula:</p> | |||||
<pre>R = sign(P) * sqrt(abs(P * C))</pre> | |||||
<p>This function returns very quickly and can be called as often as required without any follow-up actions as long | |||||
as the SNF Engine is active (between startupSNF...() and shutdownSNF()). This function is thread-safe and does not interfere with other scanning functions.</p> | |||||
<dl> | |||||
<dd><b>IPToCheck</b> = The IP to test.</dd> | |||||
<dd><b>returns</b> a number between -1.0 and +1.0 representing the combined probability that the IP will produce spam.</dd> | |||||
</dl> | |||||
<h4>Converting IP Reputation Figures To Weights</h4> | |||||
<p>There are a number of ways to convert a Reputation figure to a weight value. The simplest is to simply multiply | |||||
the Reputation figure by the maximum weight you wish to give to this test.</p> | |||||
<pre>SimpleWeight = R * MaxReputationWeight</pre> | |||||
<p>Since many legitimate ISPs also produce a lot of spam it might be useful to apply a bias to this weight so that | |||||
these systems appear closer to zero. For example if you applied a maximum weight of 10 and found that many ISPs | |||||
regularly scored 5 or more then you might add a Bias of -5 to bring those systems toward zero.</p> | |||||
<pre>BiasedWeight = (R * MaxReputationWeight) + Bias</pre> | |||||
<p>A more sophisticated system might allow for different weights on the positive and negative going Reputation | |||||
figures so that the amount of negative or positive weight that can be applied can be adjusted independently. Such | |||||
a system might also wish to apply a bias directly to the reputation figure before doing that calculation so that | |||||
the zero point can be adjusted to compensate for averages.</p> | |||||
<p>In a system like this if legitimate ISPs tended to get a Reputation Figure of 0.5 then the bias might be -0.5 | |||||
so that this would become the zero point. Then the positive and negative weight factors could be adjusted so that | |||||
the desired maximum and minimum weights can be achieved... Note that in this scenario the positive and negative | |||||
weight settings are not maximum values. | |||||
<pre>SplitWeight = (0 > (R + Bias)) ? ((R + Bias) * NegativeWeightFactor) : ((R + Bias) * PositiveWeightFactor) | |||||
MaximumNegativeWeight is given by (-1.0 + Bias) * NegativeWeightFactor | |||||
MaximumPositiveWeight is given by (+1.0 + Bias) * PositiveWeightFactor | |||||
When R + Bias == 0.0, the weight will be 0.</pre> | |||||
<p>The most sophisticated system might provide a graphic interface that maps the reputation figure directly | |||||
to a desired weight. This would allow the user to shape the effect of the Reputation figure any way they wish in | |||||
order to gain very tight control over their systems accuracy.</p> | |||||
<hr/> | |||||
<a name="scanBuffer"><h3>int scanBuffer(unsigned char* Bfr, int Length, char* Name, int Setup);</h3></a> | |||||
<p>This function scans an SMTP message from a buffer. A scan result block is allocated for the scan | |||||
and a handle representing the scan result block is returned. The application can then use this handle to retrieve | |||||
the scan results using the get...() functions. When the application is finished it MUST release the | |||||
scan result block with a call to closeScan().</p> | |||||
<p>The message buffer is expected to contain the raw SMTP data for the message with the local Received: | |||||
header at the top. The message should not be broken into MIME segments before it is scanned by SNFMulti. | |||||
This is important because Message Sniffer examines the entire message as well as how the message was | |||||
assembled by the originating system. Any additional processing is both unnecessary and may remove subtle | |||||
defects and artifacts that will help Message Sniffer classify the message.</p> | |||||
<p>If the message is particularly large it is acceptable to scan only the first 32K bytes of the message. | |||||
This means that if the calling application wants to scan a large incoming message before it has received | |||||
all of the DATA during the SMTP connection then it can scan the first 32K of the message and potentially | |||||
reject the remainder based on the scan result.</p> | |||||
<p>When the application is finished with the results from this scan it must release the scan result block | |||||
with a call to closeScan(). Scan result blocks are allocated as needed and then recycled in order to improve | |||||
performance. If the application fails to close the scan result blocks then the DLL will continue to | |||||
allocate additional blocks until there is no more RAM.</p> | |||||
<p>The entire scan is performed before this function returns. After that the scanning thread is no longer | |||||
considered to be active. The resulting scan result buffer may be accessed as often as needed to gather | |||||
results data from this scan without impacting any other scan operations.</p> | |||||
<p>Any number of scan...() operations may be active concurrently up to the limits of the platform.</p> | |||||
<p>The scanBuffer() function accepts two additional parameters that are passed on to the logging system | |||||
to aid in debugging.</p> | |||||
<p>The Name parameter is a null terminated string containing an identifier for the | |||||
message being scanned. This can be any name that can be used later to identify this particular message | |||||
in the log files such as a serial number, unique hash, or the message-id. For example, when the | |||||
scanFile() function is called this parameter is filled in with the path to the file that was scanned.</p> | |||||
<p>The Setup parameter is an integer representing the number of milliseconds spent so far setting up | |||||
the message to be scanned. This can be any useful metric - but generally it should represent how much | |||||
time the system has spent working on preparing and evaluating the message so far. For example, when the | |||||
scanFile() function is called this value is automatically established with the amount of time spent | |||||
opening and reading the message file.</p> | |||||
<p><b>IMPORTANT:</b> SNF expects to identify the source IP for the message by searching Received: headers | |||||
in the message. The application must ensure that the local Received: header is present as the first | |||||
Received: header in the message in order for this search to be accurate. If necessary the calling application can | |||||
simulate the local received header using the following minimal form:</p> | |||||
<p><pre>Received: from connecting.mta.example.com [12.34.56.78] by this.scanning.system</pre></p> | |||||
<p>where <b><i>connecting.mta.example.com</i></b> is the optional reverse DNS resolved for the connecting MTA; | |||||
<b><i>12.34.56.78</i></b> is the IP of the connecting MTA; and <b><i>by this.scanning.system</i></b> is an optional | |||||
reference to the calling application.</p> | |||||
</font><dl> | |||||
<dd><font face="sans-serif"><b>Bfr</b> = a pointer to the buffer that is to be scanned.</font></dd> | |||||
<dd><font face="sans-serif"><b>Length</b> = the length of the message buffer in bytes.</font></dd> | |||||
<dd><font face="sans-serif"><b>Name</b> = a message identifier as a null terminated string.</font></dd> | |||||
<dd><font face="sans-serif"><b>Setup</b> = the time in milliseconds already spent setting up this message for scanning.</font></dd> | |||||
<dd><font face="sans-serif"><b>returns</b> a handle to the scan result block upon success otherwise an error code: | |||||
</font><dl> | |||||
<dd><font face="sans-serif">snf_ERROR_NO_HANDLE - There was a problem allocating a scan result block.</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_SCAN_FAILED - There was a problem performing the scan.</font></dd> | |||||
</dl> | |||||
<p><font face="sans-serif">In general a result > 0 indicates a valid scan handle and a result <= 0 indicates an error. | |||||
NOTE that the scan may have failed even if you get a valid handle. The scan result code you retrieve | |||||
from get...() may indicate an error. <a href="#ResultCodes">See Result Codes</a> for details.</font></p> | |||||
</dd> | |||||
</dl><font face="sans-serif"> | |||||
<hr/> | |||||
<a name="scanFile"><h3>int scanFile(char* FilePath, int Setup);</h3></a> | |||||
<p>This function scans an SMTP message from a file. A scan result block is allocated for the scan | |||||
and a handle representing the results is returned. The application can then use this handle to retrieve | |||||
the scan results using the get...() functions. When the application is finished it MUST release the | |||||
scan result block with a call to closeScan().</p> | |||||
<p>The scanFile() function is nearly identical to the <a href="#scanBuffer">scanBuffer() function (see above)</a> | |||||
except that this function accepts the path to a file (null terminated string) instead of a pointer to a message | |||||
buffer.</p> | |||||
<p>One other key difference with between scanBuffer() and scanFile() is that the SNF engine can be configured | |||||
to inject it's X- headers when scanFile() is used. These same X- headers are available to the calling application | |||||
when using scanBuffer(), however if the application wishes to pass the message file on to other additional | |||||
scanners and external processes then scanFile() might be more convenient.</p> | |||||
<p>NOTE: There are significant performance implications to scanning files and injecting headers. Each time | |||||
headers are injected into a message the message file must be rewritten. For optimal performance it is best | |||||
to collect headers from scanning tools before writing the message to disk so that the message only needs to | |||||
be written once. Extra file IO is the cost of the convenience of passing a message file to external processes.</p> | |||||
<p>The Setup time passed to scanFile() will be added to the time required to open and read the message file | |||||
prior to scanning. This value will be passed on to the logging system. For example, the calling application | |||||
might include the number of milliseconds required to perform any previous message testing and the time it | |||||
has taken to create a temporary message file for scanning. The log will then reflect the complete setup time | |||||
separately from the time required to perform the SNF message scan.</p> | |||||
<p>The FilePath will be passed on to the logging system to identify this message scan in the logs.</p> | |||||
</font><dl> | |||||
<dd><font face="sans-serif"><b>FilePath</b> = The full path (a null terminated string) to the message file to be scanned.</font></dd> | |||||
<dd><font face="sans-serif"><b>Setup</b> = The time in milliseconds spent so far preparing this message to be scanned.</font></dd> | |||||
<dd><font face="sans-serif"><b>returns</b> a handle to the scan result block upon success otherwise an error code: | |||||
</font><dl> | |||||
<dd><font face="sans-serif">snf_ERROR_NO_HANDLE - There was a problem allocating a scan result block.</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_SCAN_FAILED - There was a problem performing the scan.</font></dd> | |||||
</dl> | |||||
<p><font face="sans-serif">In general a result > 0 indicates a valid scan handle and a result <= 0 indicates an error. | |||||
NOTE that the scan may have failed even if you get a valid handle. The scan result code you retrieve | |||||
from get...() may indicate an error. <a href="#ResultCodes">See Result Codes</a> for details.</font></p> | |||||
</dd> | |||||
</dl><font face="sans-serif"> | |||||
<hr/> | |||||
<a name="getScanXHeaders"><h3>int getScanXHeaders(int ScanHandle, char** Bfr, int* Length);</h3></a> | |||||
<p>This function returns the scan result code <a href="#ResultCodes">(see Result Codes)</a> and a pointer | |||||
to a buffer containing any X- headers that were produced for the scan associated with the ScanHandle.</p> | |||||
<p>The function is passed a valid ScanHandle which identifies the scan result block to query; the address of | |||||
a char* which will be changed to point to a buffer containing any X- headers that | |||||
were produced; and the address of an integer which will be changed to the length of the | |||||
X- headers buffer.</p> | |||||
<p>If no X- headers were produced for the scan then the pointer Bfr will point to a safe empty string | |||||
and Length will be set to zero. Put another way, Bfr and Length will be consistent with an empty null terminated | |||||
string.</p> | |||||
<p>The char* Bfr and the int Length will remain valid until closeScan() is called for this ScanHandle.</p> | |||||
<p>In order for X- headers to be produced the engine must be configured properly. For details visit the | |||||
<a href="http://www.armresearch.com/support/articles/software/snfServer/config/node/logs/scan/xheaders/index.jsp"> | |||||
XHeader configuration documentation</a> on our web site.</p> | |||||
<dl> | |||||
<dd><b>ScanHandle</b> = a valid scan handle from scanBuffer() or scanFile().</dd> | |||||
<dd><b>Bfr</b> = a pointer to a char* where the char* will be changed to point to the XHeaders.</dd> | |||||
<dd><b>Length</b> = a pointer to an int where the int will be changed to the length of the XHeaders.</dd> | |||||
<dd><b>returns</b> the scan result code upon success otherwise an error code: | |||||
<dl> | |||||
<dd>snf_ERROR_NO_HANDLE - The ScanHandle is not valid.</dd> | |||||
<dd>snf_ERROR_EXCEPTION - There was a problem retrieving the data.</dd> | |||||
<dd><a href="#ResultCodes">See Result Codes</a> for other possible return values.</dd> | |||||
</dl> | |||||
</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="getScanXMLLog"><h3>int getScanXMLLog(int ScanHandle, char** Bfr, int* Length);</h3></a> | |||||
<p>This function returns the scan result code <a href="#ResultCodes">(see Result Codes)</a> and a pointer | |||||
to a buffer containing any XML Log Data that was produced for the scan associated with the ScanHandle.</p> | |||||
<p>The function is passed a valid ScanHandle which identifies the scan result block to query; the address of | |||||
a char* which will be changed to point to a buffer containing any XML Log Data that | |||||
was produced; and the address of an integer which will be changed to the length of the | |||||
XML Log Data buffer.</p> | |||||
<p>If no XML Log Data was produced for the scan then the pointer Bfr will point to a safe empty string | |||||
and Length will be set to zero. Put another way, Bfr and Length will be consistent with an empty null terminated | |||||
string.</p> | |||||
<p>The char* Bfr and the int Length will remain valid until closeScan() is called for this ScanHandle.</p> | |||||
<p>In order for XML Log Data to be produced the engine must be configured properly. For details visit the | |||||
<a href="http://www.armresearch.com/support/articles/software/snfServer/config/node/logs/scan/xml.jsp"> | |||||
XML Log configuration documentation</a> on our web site.</p> | |||||
<dl> | |||||
<dd><b>ScanHandle</b> = a valid scan handle from scanBuffer() or scanFile().</dd> | |||||
<dd><b>Bfr</b> = a pointer to a char* where the char* will be changed to point to the XML Log Data.</dd> | |||||
<dd><b>Length</b> = a pointer to an int where the int will be changed to the length of the XML Log Data.</dd> | |||||
<dd><b>returns</b> the scan result code upon success otherwise an error code: | |||||
<dl> | |||||
<dd>snf_ERROR_NO_HANDLE - The ScanHandle is not valid.</dd> | |||||
<dd>snf_ERROR_EXCEPTION - There was a problem retrieving the data.</dd> | |||||
<dd><a href="#ResultCodes">See Result Codes</a> for other possible return values.</dd> | |||||
</dl> | |||||
</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="getScanClassicLog"><h3>int getScanClassicLog(int ScanHandle, char** Bfr, int* Length);</h3></a> | |||||
<p>This function returns the scan result code <a href="#ResultCodes">(see Result Codes)</a> and a pointer | |||||
to a buffer containing any Classic Log Data that was produced for the scan associated with the ScanHandle.</p> | |||||
<p>The function is passed a valid ScanHandle which identifies the scan result block to query; the address of | |||||
a char* which will be changed to point to a buffer containing any Classic Log Data that | |||||
was produced; and the address of an integer which will be changed to the length of the | |||||
Classic Log Data buffer.</p> | |||||
<p>If no Classic Log Data was produced for the scan then the pointer Bfr will point to a safe empty string | |||||
and Length will be set to zero. Put another way, Bfr and Length will be consistent with an empty null terminated | |||||
string.</p> | |||||
<p>The char* Bfr and the int Length will remain valid until closeScan() is called for this ScanHandle.</p> | |||||
<p>In order for XML Log Data to be produced the engine must be configured properly. For details visit the | |||||
<a href="http://www.armresearch.com/support/articles/software/snfServer/config/node/logs/scan/classic.jsp"> | |||||
Classic Log configuration documentation</a> on our web site.</p> | |||||
<dl> | |||||
<dd><b>ScanHandle</b> = a valid scan handle from scanBuffer() or scanFile().</dd> | |||||
<dd><b>Bfr</b> = a pointer to a char* where the char* will be changed to point to the Classic Log Data.</dd> | |||||
<dd><b>Length</b> = a pointer to an int where the int will be changed to the length of the Classic Log Data.</dd> | |||||
<dd><b>returns</b> the scan result code upon success otherwise an error code: | |||||
<dl> | |||||
<dd>snf_ERROR_NO_HANDLE - The ScanHandle is not valid.</dd> | |||||
<dd>snf_ERROR_EXCEPTION - There was a problem retrieving the data.</dd> | |||||
<dd><a href="#ResultCodes">See Result Codes</a> for other possible return values.</dd> | |||||
</dl> | |||||
</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="getScanResult"><h3>int getScanResult(int ScanHandle);</h3></a> | |||||
<p>This function returns the scan result code <a href="#ResultCodes">(see Result Codes)</a> | |||||
for the scan associated with the ScanHandle.</p> | |||||
<dl> | |||||
<dd><b>ScanHandle</b> = a valid scan handle from scanBuffer() or scanFile().</dd> | |||||
<dd><b>returns</b> the scan result code upon success otherwise an error code: | |||||
<dl> | |||||
<dd>snf_ERROR_NO_HANDLE - The ScanHandle is not valid.</dd> | |||||
<dd><a href="#ResultCodes">See Result Codes</a> for other possible return values.</dd> | |||||
</dl> | |||||
</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="closeScan"><h3>int closeScan(int ScanHandle);</h3></a> | |||||
<p>This function closes a ScanHandle and releases the associated Scan Result Block to the pool. This | |||||
function MUST be called once for each ScanHandle produced in a scan...() function. Once this function | |||||
is called the ScanHandle is no longer valid and any pointers returned by previous | |||||
calls to get...() functions should be discarded (forgotten, not freed!)</p> | |||||
<dl> | |||||
<dd><b>ScanHandle</b> = a valid scan handle from scanBuffer() or scanFile().</dd> | |||||
<dd><b>returns:</b> | |||||
<dl> | |||||
<dd>snf_SUCCESS - The ScanHandle was closed successfully.</dd> | |||||
<dd>snf_ERROR_NO_HANDLE - The ScanHandle is not valid.</dd> | |||||
<dd>snf_ERROR_EXCEPTION - There was a problem closing the ScanHandle.</dd> | |||||
</dl> | |||||
</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="shutdownSNF"><h3>int shutdownSNF();</h3></a> | |||||
<p>This function shuts down the SNFMulti engine. All previously allocated ScanHandles MUST be closed | |||||
before this function is called. This should be the last function in the DLL that is called by your | |||||
application (call no other SNFMultiDLL functions after this).</p> | |||||
<dl> | |||||
<dd><b>returns:</b> | |||||
<dl> | |||||
<dd>snf_SUCCESS - The shutdown was successful.</dd> | |||||
<dd>snf_ERROR_EXCEPTION - An error occurred during shutdown.</dd> | |||||
</dl> | |||||
</dd> | |||||
</dl> | |||||
<hr/> | |||||
<a name="ResultCodes"><h3>Result Codes</h3></a> | |||||
<h4>Error Codes</h4> | |||||
</font><dl> | |||||
<dd><font face="sans-serif">snf_SUCCESS = 0</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_CMD_LINE = 65</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_LOG_FILE = 66</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_RULE_FILE = 67</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_RULE_DATA = 68</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_RULE_AUTH = 73</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_MSG_FILE = 69</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_ALLOCATION = 70</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_BAD_MATRIX = 71</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_MAX_EVALS = 72</font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_UNKNOWN = 99</font></dd> | |||||
<font face="sans-serif"><br/> | |||||
<dd>snf_ERROR_NO_HANDLE = -1, Invalid scan handle used or created.</dd></font> | |||||
<dd><font face="sans-serif">snf_ERROR_SCAN_FAILED = -2, An unexpected exception during a scan. </font></dd> | |||||
<dd><font face="sans-serif">snf_ERROR_EXCEPTION = -3, An unexpected exception occurred.</font></dd> | |||||
</dl><font face="sans-serif"> | |||||
<p> | |||||
<a href="http://www.armresearch.com/support/articles/software/snfServer/errors.jsp"> | |||||
See our web site for more detailed descriptions of these error codes.</a></p> | |||||
<h4>Scan Result Codes</h4> | |||||
<p>Scan results codes 0 through 63 represent normal scan results. By convention a result of | |||||
0 indicates ham (not spam); a result of 1 indicates a white-ruled message; and other non-zero | |||||
result values that are less than 64 indicate some kind of spam or malware was detected. | |||||
<a href="http://www.armresearch.com/support/articles/software/snfServer/core.jsp"> | |||||
For more details on message scan result codes please see our web site.</a></p> | |||||
<hr/> | |||||
<div align="right"><font size="-3">Copyright (C) 2009 ARM Research Labs, LLC</font></div> | |||||
</font> | |||||
</body> | |||||
</html> |
SNFClient Readme | |||||
Copyright (c) 2010 ARM Research Laboratories | |||||
Command line client for SNF. This utility formats and processes SNF_XCI | |||||
requests through the SNF Engine working on the local machine. In general | |||||
this utility can be used as a replacement for the earlier SNF command | |||||
line scanner. It is also useful for other uses such as debugging and | |||||
communicating with GBUdb. | |||||
Note: Unlike prior versions of SNF, this command line utility does not | |||||
need to be "branded" (renamed for the SNF license id). | |||||
_________ | |||||
Help Mode | |||||
SNFClient.exe | |||||
When called with no command line parameters the utility produces | |||||
help and version information. | |||||
__________ | |||||
Debug Mode | |||||
SNFDebugClient.exe | |||||
When "debug" or "Debug" appears in the path to the program name | |||||
or if the program's name is altered to include the word "debug" or | |||||
"Debug" then the program will produce additional information about | |||||
it's operation to aid in debugging problems. This includes the | |||||
entire raw SNF_XCI request and response. | |||||
__________________ | |||||
Message Scan Modes | |||||
These modes are used to scan email message files (the data part of | |||||
smtp). This utility can be used as a drop-in replacement for previous | |||||
verions of SNF (Message Sniffer) for scanning messages. However, this | |||||
new version does not need to be "branded" (renamed for the license id) | |||||
and will ignore the authentication string if it is provided. Also, | |||||
since the newer version of SNF uses a client-server model and not a | |||||
peer-server model, there is no need for a "persistent" mode. | |||||
If "persistent" is passed to this utility on the command line as it | |||||
would be used in prior versions of SNF then it will be treated like | |||||
a file name and the scan will normally fail since a file named | |||||
"persistent" is not likely to exist. | |||||
SNFClient.exe <FileNameToScan> | |||||
Scan Mode: Scans <FileNameToScan> and returns a result code. | |||||
SNFClient.exe <authenticationxx> <FileNameToScan> | |||||
Compatibility Mode: Ignores <authenticationxx> then scans the | |||||
<FileNameToScan> and returns a result code. This mode provides | |||||
drop-in compatibility with previous versions of SNF. | |||||
SNFClient.exe -xhdr <FileNameToScan> | |||||
XHeader Mode: Scans <FileNameToScan> and returns the result. Also | |||||
outputs the contents of the X-Headers created by the SNF engine. If | |||||
the SNF engine is configured to inject these headers then they will | |||||
also have been injected into the <FileNameToScan>. | |||||
The SNF Engine can be configured to provide the X-Headers only to | |||||
the API without injecting them. In this case the XHeader Mode will | |||||
display the X-Headers that would be injected, but they will not | |||||
have been injected into the <FileNameToScan>. | |||||
If the SNF Engine is configured not to produce X-Headers (none) then | |||||
the XHeader Mode will not produce X-Headers because they will not | |||||
have been generated by the engine. | |||||
(note: -xhdr and -source options can be combined) | |||||
SNFClient.exe -source=<IP4Address> <FileNameToScan> | |||||
Source-IP Mode: Scans <FileNameToScan> and returns the result. The | |||||
provided source IP is injected into the scan as the first Received | |||||
header so that the scanning engine will presume the IP is the source | |||||
of the message. This allows you to pre-define the source IP for the | |||||
message when there is no other received header or when the received | |||||
headers may be incorrect or may not present the actual source of | |||||
the message. | |||||
(note: -xhdr and -source options can be combined) | |||||
_____________________________ | |||||
SNFServer Status Report Modes | |||||
SNFClient.exe -status.second | |||||
SNFClient.exe -status.minute | |||||
SNFClient.exe -status.hour | |||||
This mode returns the latest posted status report as indicated. | |||||
Normally these status reports are also posted to files in the | |||||
SNFServer workspace. | |||||
In this mode the SNFClient will return a result code (error level) | |||||
of 0 when the request is successful and 99 (or some nonzero value) | |||||
when the request is not successful. This allows the SNFClient to | |||||
be used to verify that the SNFServer is running. | |||||
Note: In most other modes the SNFClient returns a fail-safe 0 | |||||
result code to avoid tagging messages as spam when there are errors. | |||||
________________________ | |||||
XCI Server Command Modes | |||||
These features will expand as needed in later versions. | |||||
SNFClient.exe -shutdown | |||||
If the SNF Engine is running in an application that accepts SNF_XCI | |||||
server commands then this mode will send that command. The shutdown | |||||
command may have no effect if the application does not use the SNF_XCI | |||||
server commnand interface or does not recognize the command. | |||||
___________ | |||||
GBUdb Modes | |||||
These modes are used to communicate with the GBUdb system on the | |||||
local node. It is possible to test (read out) an IP record or make | |||||
any of a number of changes to IP data in the GBUdb. | |||||
SNFClient.exe -test <IP4Address> | |||||
Returns the current GBUdb statistics for the <IP4Address> | |||||
SNFClient also returns a result code that matches the GBUdb range | |||||
for the tested IP. These ranges are defined in the SNFServer | |||||
configuration file. By default they are: | |||||
20 - Truncate | |||||
63 - Black | |||||
40 - Caution | |||||
0 - Normal | |||||
SNFClient.exe -set <IP4Address> <flag> <bad> <good> | |||||
Creates or updates the data for <IP4Address> as provided. The | |||||
<IP4Address> must be provided as well as at least one of | |||||
<flag>, <bad>, and <good>. If <flag>, <bad>, or <good> are | |||||
to be left unchanged then they should be entered as a dash "-". | |||||
Examples: | |||||
Set all data for an IP. The flag will be "ugly", the bad count | |||||
will be 0 and the good count will be 1000. | |||||
SNFClient.exe -set 12.34.56.78 Ugly 0 1000 | |||||
Set the flag to "ignore" and do not change the counts. | |||||
SNFClient.exe -set 12.34.56.78 ignore - - | |||||
Set the good count to 400 and do not change anything else. | |||||
SNFClient.exe -set 12.34.56.78 - - 400 | |||||
SNFClient.exe -good <IP4Address> | |||||
Creates or updates statistics for the <IP4Address>. Increases the | |||||
good count by one. (Record a good event) | |||||
SNFClient.exe -bad <IP4Address> | |||||
Creates or updates statistics for the <IP4Address>. Increases the | |||||
bad count by one. (Record a bad event) | |||||
SNFClient.exe -drop <IP4Address> | |||||
Removes all local data for the <IP4Address>. Anything the local | |||||
system "knows" about the IP is forgotten. Next time the IP is | |||||
encountered it will be treated as new. | |||||
____________________ | |||||
For More Information | |||||
See www.armresearch.com | |||||
Copyright (C) 2007-2008 Arm Research Labs, LLC. | |||||
SNF_Server V3.0 installation brief | |||||
Copyright (c) 2010 ARM Research Laboratories | |||||
This is a generalized guide. For specific platform guides see: | |||||
http://www.armresearch.com/support/articles/installation/index.jsp | |||||
Create a directory for SNF_Server. ( c:\SNF or /var/spool/snfilter ) | |||||
Copy all of the files to that directory. | |||||
Make a copy of the SNFServer<version>.exe file and give it the name | |||||
SNFServer.exe. Later on if newer versions are provided you will | |||||
be able to keep track of them by name and swap newer versions into | |||||
place by copying them over your SNFServer.exe file. If you decide | |||||
you have to go back to a previous version then you will be able to | |||||
do that easily by deleting your SNFServer.exe file and copying the | |||||
version you wish to use into place. | |||||
Modify the identity.xml file to match your SNF license ID and your | |||||
authentication string. | |||||
Download your .snf file and place that in the SNF_Server working | |||||
directory. | |||||
RULEBASE UPDATES (NEW!): The latest version of the SNFServer engine | |||||
includes a mechanism that will run an a script when the rulebase file | |||||
on our server is newer than the active file in SNF. By default this | |||||
feature is configured to run the included getRulebase script. If | |||||
the script is not successful it will be launched again every 3 minutes | |||||
until the rulebase file is successfully updated. | |||||
Be sure to modify the top of the getRulebase script to include | |||||
your correct license ID, authentication string, and working directory. | |||||
Be sure to verify that the <update-script/> section of your snf_engine | |||||
file is correct (points to the correct location of getRulebase). | |||||
getRulebase uses wget and gzip (included for your convenience in | |||||
the Win* distribution. See About-Wget-and-Gzip.txt.). These are open | |||||
source utilities for downloading files from web servers and unzipping | |||||
those files -- in this case, SNF rulebase files. | |||||
If you have any gateways or other internal systems that will relay | |||||
mail to SNF then include their IPs in GBUdbIgnoreList.txt. The GBUdb | |||||
component of SNF uses the IPs in this list to determine the actual | |||||
source IP for a message by reviewing the Received headers. Each | |||||
Received header is evaluated in turn. If the source (connect) IP is | |||||
found in the Ignore list then that Received IP is considered to be | |||||
part of your infrastructure and is ignored. The first Received IP | |||||
found that is NOT in the Ignore list is selected as the source IP. | |||||
The GBUdbIgnoreList is a "safety net" that ensures the listed IPs are | |||||
present in your GBUdb with their Ignore flag set. It is loaded every | |||||
time the configuration is changed, SNFServer is started, or a new | |||||
rulebase is loaded. This way if your GBUdb database is lost then your | |||||
critical infrastructure will be re-listed in the new .gbx file that | |||||
is created. | |||||
The ignore list allows only SINGLE IP ENTRIES. This can be a problem | |||||
in some cases - such as when you want to ignore large blocks of network | |||||
addresses. | |||||
SNF can learn to Ignore large blocks of IPs using the <drilldown/> | |||||
feature. For example if you want to ignore all of 12.34.56.0/24 then | |||||
you can make an entry in the <drilldown/> training section like this: | |||||
<training on-off='on'> | |||||
... | |||||
<drilldown> | |||||
<received ordinal='0' find='[12.34.56.'/> | |||||
</drilldown> | |||||
... | |||||
</training> | |||||
GBUdb learns the behavior of source IPs so it is important that GBUdb | |||||
knows any friendly sources that might send spammy messages to your | |||||
server or else it will learn that those sources are not to be trusted. | |||||
Since not all friendly spam sources can be identified by IP ahead of | |||||
time, there are features in the <training/> section of snf_engine.xml | |||||
that allow you to adjust the training scenarios to compensate. The | |||||
most likely of these is that you may wish to bypass training for | |||||
messages that are to your support addresses or spam submission | |||||
addresses. For example: | |||||
<training on-off='on'> | |||||
... | |||||
<bypass> | |||||
<header name='To:' find='support@example.com'/> | |||||
<header name='To:' find='spam@example.com'/> | |||||
</bypass> | |||||
... | |||||
</training> | |||||
Evaluate the snf_engine.xml file carefully. In most cases the | |||||
default settings are appropriate, however you may want to alter | |||||
some of the settings to match your system policies or particular | |||||
installation. | |||||
IMPORTANT: Be sure that any file paths / directories referenced in | |||||
the configuration file exist on your system and that SNF has full | |||||
access rights to these - especially the SNF working directory. | |||||
** If you selected a working directory for SNF other than c:\SNF\ | |||||
then be sure you have changed these paths in the top of your | |||||
snf_engine.xml file. Pay close attentiont to these 5 elements: | |||||
<node identity='c:/SNF/identity.xml'> | |||||
<log path='c:/SNF/'/> | |||||
<rulebase path='c:/SNF/'/> | |||||
<workspace path='c:/SNF/'/> | |||||
<update-script ... call='c:/SNF/getRulebase.cmd' ... /> | |||||
Once you are happy with your configuration and you have all of your | |||||
files and directories in place (including your .snf file) then you | |||||
can start SNF_Server. | |||||
The command line (from inside the SNF workspace) is: | |||||
SNFServer.exe snf_engine.xml | |||||
That is: SNFServer <configuration> | |||||
If you want to lauch SNFServer from some other location it would be | |||||
best to use the entire path for both the SNFServer engine and the | |||||
configuration file: | |||||
c:\SNF\SNFServer.exe c:\SNF\snf_engine.xml | |||||
You should begin by testing SNFServer by running it in a command line | |||||
window where you can watch it's output. | |||||
Once you are happy with it then you will probably want to run it as | |||||
a service using a utility such as the srvany utility from the win2k | |||||
toolkit, or detached as a daemon on *nix systems (snfctrl file example | |||||
included). | |||||
This section of our site might be helpful: | |||||
http://www.armresearch.com/support/articles/installation/serviceSetup/index.jsp | |||||
SNFServer is the server side of a client/server system. In order to | |||||
scan messages you will need to use the client utility (SNFClient.exe | |||||
or SNFIMailShim.exe) to scan messages. | |||||
SNFClient.exe is a drop-in replacement for the production (2-3.x) | |||||
SNF program when it is called from Declude or mxGuard or other similar | |||||
software. There is no need to "brand" the SNFClient.exe | |||||
program and it is not necessary to include the authentication string | |||||
on the command line -- however, if you do it will be accepted and | |||||
ignored without an error. | |||||
SNFServer MUST be running for SNFClient to work. If SNFClient cannot | |||||
reach SNFServer then it will wait for quite a while as it attempts to | |||||
make contact. | |||||
Here are a few ways to call SNFClient.exe: | |||||
SNFClient.exe -shutdown | |||||
Sends the Shutdown command to the SNF_Server. | |||||
SNFClient.exe authenticationxx filetoscan | |||||
Compatibility mode - ignores authenticationxx and scans filetoscan. | |||||
SNFClient.exe filetoscan | |||||
Normal scan mode - scans filetoscan. | |||||
SNFClient.exe -xhdr filetoscan | |||||
XHDR scan mode - scans filetoscan and returns X Headers. | |||||
See the SNFClient_Readme.txt file for details. | |||||
The SNF Client/Server pair communicate using short XML messages via a local | |||||
TCP connection (typically to port 9001). Examples of SNF_XCI messages are | |||||
included in snf_xci.xml (not a well formed xml file! - just some examples). | |||||
It is possible to communicate directly with the SNF_Server engine via TCP | |||||
from your software using the SNF_XCI (SNF XML Command Interface) protocol. The | |||||
server expects to see one connection per request. The client sends an SNF_XCI | |||||
request to the server. The server responds with an appropriate SNF_XCI | |||||
formatted response and terminates the connection. | |||||
Requests and responses are expected to terminate with a newline character. | |||||
You can see the XCI protocol at work by running the SNFClient in debug mode | |||||
(SNFdebugClient). | |||||
If you run into trouble check out our web site: www.armresearch.com and/or | |||||
contact us by email: support@armresearch.com | |||||
____________________ | |||||
For More Information | |||||
See www.armresearch.com | |||||
Copyright (C) 2007-2008 Arm Research Labs, LLC. |
README file for the VS 2008 CPP sample project | |||||
Copyright (c) 2009 ARM Research Laboratories | |||||
This README file gives an overview of the VS 2008 CPP sample project. | |||||
This project links the sample CPP file CPPSample\main.cpp with the | |||||
SNFMulti import library. | |||||
To build this application: | |||||
1) Open VS2008CPPSampls\VS2008CPPSample.sln with VS 2008. | |||||
2) Select "x64" (if available) or "win32" for the platform. | |||||
3) In the project, open main.cpp. Modify the initial value of | |||||
ConfigurationPath as necessary to specify the location of the | |||||
SNFServer configuration file. | |||||
4) Build. | |||||
5) Ensure that the path in VS2008 includes the directory containing | |||||
SNFMulti.dll. If needed, add the directory by: | |||||
a) Right-click on "VS2008CPPSample" in the VS2008 Solution | |||||
Explorer, and select "Properties". | |||||
b) Choose "All Configurations" for the Configuration. | |||||
c) If your installation supports the x64 platform: | |||||
i) Choose "x64" for the Platform. | |||||
ii) Select Configuration Properties->Debugging. | |||||
iii) Add "path=..\64bitDll" to the Environment command. | |||||
d) Choose "Win32" for the Platform. | |||||
e) Add "path=..\32bitDll" to the Environment command. | |||||
6) Run. | |||||
In order to create an import library, do the following: | |||||
1) Open a VS2008 command prompt (Tools->Visual Studio 2008 Command | |||||
Prompt). | |||||
2) Change to the 32bitDll directory of the SDK. | |||||
3) Enter the command: | |||||
LIB /MACHINE:x86 /DEF:snfmulti.def /name:snfmulti.dll /out:vs2008_snfmulti.lib | |||||
This creates the vs2008_snfmulti.lib import library for the win32 | |||||
platform. To create an inport library for the x64 platform: | |||||
4) Change to the 64bitDll directory of the SDK. | |||||
5) Enter the command: | |||||
LIB /MACHINE:x64 /DEF:snfmulti.def /name:snfmulti.dll /out:vs2008_snfmulti.lib | |||||
This creates the vs2008_snfmulti.lib import library for the x64 | |||||
platform. |
| |||||
Microsoft Visual Studio Solution File, Format Version 10.00 | |||||
# Visual Studio 2008 | |||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VS2008CPPSample", "VS2008CPPSample.vcproj", "{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Win32 = Debug|Win32 | |||||
Debug|x64 = Debug|x64 | |||||
Release|Win32 = Release|Win32 | |||||
Release|x64 = Release|x64 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Debug|Win32.ActiveCfg = Debug|Win32 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Debug|Win32.Build.0 = Debug|Win32 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Debug|x64.ActiveCfg = Debug|x64 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Debug|x64.Build.0 = Debug|x64 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Release|Win32.ActiveCfg = Release|Win32 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Release|Win32.Build.0 = Release|Win32 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Release|x64.ActiveCfg = Release|x64 | |||||
{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}.Release|x64.Build.0 = Release|x64 | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
EndGlobal |
<?xml version="1.0" encoding="UTF-8"?> | |||||
<VisualStudioProject | |||||
ProjectType="Visual C++" | |||||
Version="9.00" | |||||
Name="VS2008CPPSample" | |||||
ProjectGUID="{34C4ED82-49CD-49B9-9B8E-1BB76B04BC8B}" | |||||
Keyword="Win32Proj" | |||||
TargetFrameworkVersion="0" | |||||
> | |||||
<Platforms> | |||||
<Platform | |||||
Name="Win32" | |||||
/> | |||||
<Platform | |||||
Name="x64" | |||||
/> | |||||
</Platforms> | |||||
<ToolFiles> | |||||
</ToolFiles> | |||||
<Configurations> | |||||
<Configuration | |||||
Name="Debug|Win32" | |||||
OutputDirectory="Debug" | |||||
IntermediateDirectory="Debug" | |||||
ConfigurationType="1" | |||||
> | |||||
<Tool | |||||
Name="VCPreBuildEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCCustomBuildTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXMLDataGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCWebServiceProxyGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCMIDLTool" | |||||
/> | |||||
<Tool | |||||
Name="VCCLCompilerTool" | |||||
Optimization="0" | |||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_USE_32BIT_TIME_T" | |||||
MinimalRebuild="true" | |||||
BasicRuntimeChecks="3" | |||||
RuntimeLibrary="3" | |||||
UsePrecompiledHeader="0" | |||||
WarningLevel="3" | |||||
DebugInformationFormat="4" | |||||
/> | |||||
<Tool | |||||
Name="VCManagedResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPreLinkEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCLinkerTool" | |||||
AdditionalDependencies="vs2008_snfmulti.lib" | |||||
AdditionalLibraryDirectories="..\32bitDll" | |||||
GenerateDebugInformation="true" | |||||
SubSystem="1" | |||||
TargetMachine="1" | |||||
/> | |||||
<Tool | |||||
Name="VCALinkTool" | |||||
/> | |||||
<Tool | |||||
Name="VCManifestTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXDCMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCBscMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCFxCopTool" | |||||
/> | |||||
<Tool | |||||
Name="VCAppVerifierTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPostBuildEventTool" | |||||
/> | |||||
</Configuration> | |||||
<Configuration | |||||
Name="Debug|x64" | |||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)" | |||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" | |||||
ConfigurationType="1" | |||||
> | |||||
<Tool | |||||
Name="VCPreBuildEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCCustomBuildTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXMLDataGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCWebServiceProxyGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCMIDLTool" | |||||
TargetEnvironment="3" | |||||
/> | |||||
<Tool | |||||
Name="VCCLCompilerTool" | |||||
Optimization="0" | |||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;" | |||||
MinimalRebuild="true" | |||||
BasicRuntimeChecks="3" | |||||
RuntimeLibrary="3" | |||||
UsePrecompiledHeader="0" | |||||
WarningLevel="3" | |||||
DebugInformationFormat="3" | |||||
/> | |||||
<Tool | |||||
Name="VCManagedResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPreLinkEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCLinkerTool" | |||||
AdditionalDependencies="vs2008_snfmulti.lib" | |||||
AdditionalLibraryDirectories="..\64bitDll" | |||||
GenerateDebugInformation="true" | |||||
SubSystem="1" | |||||
TargetMachine="17" | |||||
/> | |||||
<Tool | |||||
Name="VCALinkTool" | |||||
/> | |||||
<Tool | |||||
Name="VCManifestTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXDCMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCBscMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCFxCopTool" | |||||
/> | |||||
<Tool | |||||
Name="VCAppVerifierTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPostBuildEventTool" | |||||
/> | |||||
</Configuration> | |||||
<Configuration | |||||
Name="Release|Win32" | |||||
OutputDirectory="Release" | |||||
IntermediateDirectory="Release" | |||||
ConfigurationType="1" | |||||
> | |||||
<Tool | |||||
Name="VCPreBuildEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCCustomBuildTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXMLDataGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCWebServiceProxyGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCMIDLTool" | |||||
/> | |||||
<Tool | |||||
Name="VCCLCompilerTool" | |||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;" | |||||
RuntimeLibrary="2" | |||||
UsePrecompiledHeader="0" | |||||
WarningLevel="3" | |||||
DebugInformationFormat="3" | |||||
/> | |||||
<Tool | |||||
Name="VCManagedResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPreLinkEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCLinkerTool" | |||||
AdditionalDependencies="vs2008_snfmulti.lib" | |||||
AdditionalLibraryDirectories=""C:\Users\adeniz\Desktop\microNeil\codeDevelopment\PKG-SNF-SDK-WIN\trunk\32bitDll"" | |||||
GenerateDebugInformation="true" | |||||
SubSystem="1" | |||||
OptimizeReferences="2" | |||||
EnableCOMDATFolding="2" | |||||
TargetMachine="1" | |||||
/> | |||||
<Tool | |||||
Name="VCALinkTool" | |||||
/> | |||||
<Tool | |||||
Name="VCManifestTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXDCMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCBscMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCFxCopTool" | |||||
/> | |||||
<Tool | |||||
Name="VCAppVerifierTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPostBuildEventTool" | |||||
/> | |||||
</Configuration> | |||||
<Configuration | |||||
Name="Release|x64" | |||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)" | |||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" | |||||
ConfigurationType="1" | |||||
> | |||||
<Tool | |||||
Name="VCPreBuildEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCCustomBuildTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXMLDataGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCWebServiceProxyGeneratorTool" | |||||
/> | |||||
<Tool | |||||
Name="VCMIDLTool" | |||||
TargetEnvironment="3" | |||||
/> | |||||
<Tool | |||||
Name="VCCLCompilerTool" | |||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;" | |||||
RuntimeLibrary="2" | |||||
UsePrecompiledHeader="0" | |||||
WarningLevel="3" | |||||
DebugInformationFormat="3" | |||||
/> | |||||
<Tool | |||||
Name="VCManagedResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCResourceCompilerTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPreLinkEventTool" | |||||
/> | |||||
<Tool | |||||
Name="VCLinkerTool" | |||||
AdditionalDependencies="vs2008_snfmulti.lib" | |||||
AdditionalLibraryDirectories="..\64bitDll" | |||||
GenerateDebugInformation="true" | |||||
SubSystem="1" | |||||
OptimizeReferences="2" | |||||
EnableCOMDATFolding="2" | |||||
TargetMachine="17" | |||||
/> | |||||
<Tool | |||||
Name="VCALinkTool" | |||||
/> | |||||
<Tool | |||||
Name="VCManifestTool" | |||||
/> | |||||
<Tool | |||||
Name="VCXDCMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCBscMakeTool" | |||||
/> | |||||
<Tool | |||||
Name="VCFxCopTool" | |||||
/> | |||||
<Tool | |||||
Name="VCAppVerifierTool" | |||||
/> | |||||
<Tool | |||||
Name="VCPostBuildEventTool" | |||||
/> | |||||
</Configuration> | |||||
</Configurations> | |||||
<References> | |||||
</References> | |||||
<Files> | |||||
<Filter | |||||
Name="Header Files" | |||||
Filter="h;hpp;hxx;hm;inl;inc;xsd" | |||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" | |||||
> | |||||
<File | |||||
RelativePath="..\include\snfmultidll.h" | |||||
> | |||||
</File> | |||||
</Filter> | |||||
<Filter | |||||
Name="Resource Files" | |||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" | |||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" | |||||
> | |||||
</Filter> | |||||
<Filter | |||||
Name="Source Files" | |||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" | |||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" | |||||
> | |||||
<File | |||||
RelativePath="..\CPPSample\main.cpp" | |||||
> | |||||
</File> | |||||
</Filter> | |||||
</Files> | |||||
<Globals> | |||||
</Globals> | |||||
</VisualStudioProject> |
<?xml version="1.0" encoding="utf-8"?><VisualStudioUserFile ProjectType="Visual C++" Version="9.00" ShowAllFiles="true"></VisualStudioUserFile> |
README file for the VS 2008 C# sample project | |||||
Copyright (c) 2009 ARM Research Laboratories | |||||
This README file gives an overview of the VS 2008 C# sample project. | |||||
This project links the sample C# file CSSample\main.cs with the | |||||
SNFMulti DLL library. | |||||
To build this application: | |||||
1) Open VS2008CSSample\VS2008CSSample.sln with VS 2008. | |||||
2) Select "Any CPU", "x64" or "x86" for the platform. | |||||
3) In the project, open main.cs. | |||||
4) Modify the initial value of ConfigurationPath as necessary to | |||||
specify the location of the SNFServer configuration file. The | |||||
defaults assume that the configuration file name is | |||||
"snf_engine.xml", and is located in the same directory as the | |||||
VS2008CSSample.sln. | |||||
5) Modify the initial value of SNFMULTI_DLL as necessary to specify | |||||
the location of the SNFMulti.dll file. | |||||
6) Build. | |||||
7) Run. |
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{31A86551-C6D7-4BFA-A5C5-8748254E6368}</ProjectGuid> | |||||
<ProductVersion>9.0.30729</ProductVersion> | |||||
<SchemaVersion>2.0</SchemaVersion> | |||||
<OutputType>Exe</OutputType> | |||||
<NoStandardLibraries>false</NoStandardLibraries> | |||||
<AssemblyName>ConsoleApplication</AssemblyName> | |||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
<RootNamespace>VS2008CSSample</RootNamespace> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<Optimize>false</Optimize> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<DebugType>pdbonly</DebugType> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<OutputPath>bin\x64\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<DebugType>full</DebugType> | |||||
<PlatformTarget>x64</PlatformTarget> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | |||||
<OutputPath>bin\x64\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<Optimize>true</Optimize> | |||||
<DebugType>pdbonly</DebugType> | |||||
<PlatformTarget>x64</PlatformTarget> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<OutputPath>bin\x86\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<DebugType>full</DebugType> | |||||
<PlatformTarget>x86</PlatformTarget> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | |||||
<OutputPath>bin\x86\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<Optimize>true</Optimize> | |||||
<DebugType>pdbonly</DebugType> | |||||
<PlatformTarget>x86</PlatformTarget> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="System" /> | |||||
<Reference Include="System.Core" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Data.DataSetExtensions" /> | |||||
<Reference Include="System.Xml" /> | |||||
<Reference Include="System.Xml.Linq" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="..\CSSample\main.cs"> | |||||
<Link>main.cs</Link> | |||||
</Compile> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" /> | |||||
<ProjectExtensions> | |||||
<VisualStudio AllowExistingFolder="true" /> | |||||
</ProjectExtensions> | |||||
</Project> |
| |||||
Microsoft Visual Studio Solution File, Format Version 10.00 | |||||
# Visual Studio 2008 | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VS2008CSSample", "VS2008CSSample.csproj", "{31A86551-C6D7-4BFA-A5C5-8748254E6368}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Any CPU = Debug|Any CPU | |||||
Debug|x64 = Debug|x64 | |||||
Debug|x86 = Debug|x86 | |||||
Release|Any CPU = Release|Any CPU | |||||
Release|x64 = Release|x64 | |||||
Release|x86 = Release|x86 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Debug|x64.ActiveCfg = Debug|x64 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Debug|x64.Build.0 = Debug|x64 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Debug|x86.ActiveCfg = Debug|x86 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Debug|x86.Build.0 = Debug|x86 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Release|x64.ActiveCfg = Release|x64 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Release|x64.Build.0 = Release|x64 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Release|x86.ActiveCfg = Release|x86 | |||||
{31A86551-C6D7-4BFA-A5C5-8748254E6368}.Release|x86.Build.0 = Release|x86 | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
EndGlobal |
README file for the VS 2008 VB sample project | |||||
Copyright (c) 2009 ARM Research Laboratories | |||||
This README file gives an overview of the VS 2008 VB sample project. | |||||
This project links the sample VB file VBSample\main.cpp with the | |||||
SNFMulti DLL library. | |||||
To build this application: | |||||
1) Open VS2008VBSample\VS2008VBSample.sln with VS 2008. | |||||
2) Select "Any CPU", "x64" or "x86" for the platform. | |||||
3) In the project, open main.vb. | |||||
4) Modify the initial value of ConfigurationPath as necessary to | |||||
specify the location of the SNFServer configuration file. The | |||||
defaults assume that the configuration file name is | |||||
"snf_engine.xml", and is located in the same directory as the | |||||
VS2008VBSample.sln. | |||||
5) Modify the initial value of SNFMULTI_DLL as necessary to specify | |||||
the location of the SNFMulti.dll file. | |||||
6) Build. | |||||
7) Run. |
| |||||
Microsoft Visual Studio Solution File, Format Version 10.00 | |||||
# Visual Studio 2008 | |||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VS2008VBSample", "VS2008VBSample\VS2008VBSample.vbproj", "{DB74E346-D064-4912-804F-342DF837388B}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Any CPU = Debug|Any CPU | |||||
Debug|x64 = Debug|x64 | |||||
Debug|x86 = Debug|x86 | |||||
Release|Any CPU = Release|Any CPU | |||||
Release|x64 = Release|x64 | |||||
Release|x86 = Release|x86 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Debug|x64.ActiveCfg = Debug|x64 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Debug|x64.Build.0 = Debug|x64 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Debug|x86.ActiveCfg = Debug|x86 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Debug|x86.Build.0 = Debug|x86 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Release|x64.ActiveCfg = Release|x64 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Release|x64.Build.0 = Release|x64 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Release|x86.ActiveCfg = Release|x86 | |||||
{DB74E346-D064-4912-804F-342DF837388B}.Release|x86.Build.0 = Release|x86 | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
EndGlobal |
'------------------------------------------------------------------------------ | |||||
' <auto-generated> | |||||
' This code was generated by a tool. | |||||
' Runtime Version:2.0.50727.3074 | |||||
' | |||||
' Changes to this file may cause incorrect behavior and will be lost if | |||||
' the code is regenerated. | |||||
' </auto-generated> | |||||
'------------------------------------------------------------------------------ | |||||
Option Strict On | |||||
Option Explicit On | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |||||
<MySubMain>false</MySubMain> | |||||
<SingleInstance>false</SingleInstance> | |||||
<ShutdownMode>0</ShutdownMode> | |||||
<EnableVisualStyles>true</EnableVisualStyles> | |||||
<AuthenticationMode>0</AuthenticationMode> | |||||
<ApplicationType>2</ApplicationType> | |||||
<SaveMySettingsOnExit>true</SaveMySettingsOnExit> | |||||
</MyApplicationData> |
Imports System | |||||
Imports System.Reflection | |||||
Imports System.Runtime.InteropServices | |||||
' General Information about an assembly is controlled through the following | |||||
' set of attributes. Change these attribute values to modify the information | |||||
' associated with an assembly. | |||||
' Review the values of the assembly attributes | |||||
<Assembly: AssemblyTitle("VS2008VBSample")> | |||||
<Assembly: AssemblyDescription("")> | |||||
<Assembly: AssemblyCompany("Microsoft")> | |||||
<Assembly: AssemblyProduct("VS2008VBSample")> | |||||
<Assembly: AssemblyCopyright("Copyright © Microsoft 2009")> | |||||
<Assembly: AssemblyTrademark("")> | |||||
<Assembly: ComVisible(False)> | |||||
'The following GUID is for the ID of the typelib if this project is exposed to COM | |||||
<Assembly: Guid("b50e67b0-4be1-4dc5-a071-1ef8ebbdd72f")> | |||||
' Version information for an assembly consists of the following four values: | |||||
' | |||||
' Major Version | |||||
' Minor Version | |||||
' Build Number | |||||
' Revision | |||||
' | |||||
' You can specify all the values or you can default the Build and Revision Numbers | |||||
' by using the '*' as shown below: | |||||
' <Assembly: AssemblyVersion("1.0.*")> | |||||
<Assembly: AssemblyVersion("1.0.0.0")> | |||||
<Assembly: AssemblyFileVersion("1.0.0.0")> |
'------------------------------------------------------------------------------ | |||||
' <auto-generated> | |||||
' This code was generated by a tool. | |||||
' Runtime Version:2.0.50727.3074 | |||||
' | |||||
' Changes to this file may cause incorrect behavior and will be lost if | |||||
' the code is regenerated. | |||||
' </auto-generated> | |||||
'------------------------------------------------------------------------------ | |||||
Option Strict On | |||||
Option Explicit On | |||||
Namespace My.Resources | |||||
'This class was auto-generated by the StronglyTypedResourceBuilder | |||||
'class via a tool like ResGen or Visual Studio. | |||||
'To add or remove a member, edit your .ResX file then rerun ResGen | |||||
'with the /str option, or rebuild your VS project. | |||||
'<summary> | |||||
' A strongly-typed resource class, for looking up localized strings, etc. | |||||
'</summary> | |||||
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0"), _ | |||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _ | |||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _ | |||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _ | |||||
Friend Module Resources | |||||
Private resourceMan As Global.System.Resources.ResourceManager | |||||
Private resourceCulture As Global.System.Globalization.CultureInfo | |||||
'<summary> | |||||
' Returns the cached ResourceManager instance used by this class. | |||||
'</summary> | |||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _ | |||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager | |||||
Get | |||||
If Object.ReferenceEquals(resourceMan, Nothing) Then | |||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("VS2008VBSample.Resources", GetType(Resources).Assembly) | |||||
resourceMan = temp | |||||
End If | |||||
Return resourceMan | |||||
End Get | |||||
End Property | |||||
'<summary> | |||||
' Overrides the current thread's CurrentUICulture property for all | |||||
' resource lookups using this strongly typed resource class. | |||||
'</summary> | |||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _ | |||||
Friend Property Culture() As Global.System.Globalization.CultureInfo | |||||
Get | |||||
Return resourceCulture | |||||
End Get | |||||
Set(ByVal value As Global.System.Globalization.CultureInfo) | |||||
resourceCulture = value | |||||
End Set | |||||
End Property | |||||
End Module | |||||
End Namespace |
<?xml version="1.0" encoding="utf-8"?> | |||||
<root> | |||||
<!-- | |||||
Microsoft ResX Schema | |||||
Version 2.0 | |||||
The primary goals of this format is to allow a simple XML format | |||||
that is mostly human readable. The generation and parsing of the | |||||
various data types are done through the TypeConverter classes | |||||
associated with the data types. | |||||
Example: | |||||
... ado.net/XML headers & schema ... | |||||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||||
<resheader name="version">2.0</resheader> | |||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||||
</data> | |||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||||
<comment>This is a comment</comment> | |||||
</data> | |||||
There are any number of "resheader" rows that contain simple | |||||
name/value pairs. | |||||
Each data row contains a name, and value. The row also contains a | |||||
type or mimetype. Type corresponds to a .NET class that support | |||||
text/value conversion through the TypeConverter architecture. | |||||
Classes that don't support this are serialized and stored with the | |||||
mimetype set. | |||||
The mimetype is used for serialized objects, and tells the | |||||
ResXResourceReader how to depersist the object. This is currently not | |||||
extensible. For a given mimetype the value must be set accordingly: | |||||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||||
that the ResXResourceWriter will generate, however the reader can | |||||
read any of the formats listed below. | |||||
mimetype: application/x-microsoft.net.object.binary.base64 | |||||
value : The object must be serialized with | |||||
: System.Serialization.Formatters.Binary.BinaryFormatter | |||||
: and then encoded with base64 encoding. | |||||
mimetype: application/x-microsoft.net.object.soap.base64 | |||||
value : The object must be serialized with | |||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||||
: and then encoded with base64 encoding. | |||||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||||
value : The object must be serialized into a byte array | |||||
: using a System.ComponentModel.TypeConverter | |||||
: and then encoded with base64 encoding. | |||||
--> | |||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||||
<xsd:element name="root" msdata:IsDataSet="true"> | |||||
<xsd:complexType> | |||||
<xsd:choice maxOccurs="unbounded"> | |||||
<xsd:element name="metadata"> | |||||
<xsd:complexType> | |||||
<xsd:sequence> | |||||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||||
</xsd:sequence> | |||||
<xsd:attribute name="name" type="xsd:string" /> | |||||
<xsd:attribute name="type" type="xsd:string" /> | |||||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||||
</xsd:complexType> | |||||
</xsd:element> | |||||
<xsd:element name="assembly"> | |||||
<xsd:complexType> | |||||
<xsd:attribute name="alias" type="xsd:string" /> | |||||
<xsd:attribute name="name" type="xsd:string" /> | |||||
</xsd:complexType> | |||||
</xsd:element> | |||||
<xsd:element name="data"> | |||||
<xsd:complexType> | |||||
<xsd:sequence> | |||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||||
</xsd:sequence> | |||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> | |||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||||
</xsd:complexType> | |||||
</xsd:element> | |||||
<xsd:element name="resheader"> | |||||
<xsd:complexType> | |||||
<xsd:sequence> | |||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||||
</xsd:sequence> | |||||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||||
</xsd:complexType> | |||||
</xsd:element> | |||||
</xsd:choice> | |||||
</xsd:complexType> | |||||
</xsd:element> | |||||
</xsd:schema> | |||||
<resheader name="resmimetype"> | |||||
<value>text/microsoft-resx</value> | |||||
</resheader> | |||||
<resheader name="version"> | |||||
<value>2.0</value> | |||||
</resheader> | |||||
<resheader name="reader"> | |||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||||
</resheader> | |||||
<resheader name="writer"> | |||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||||
</resheader> | |||||
</root> |
'------------------------------------------------------------------------------ | |||||
' <auto-generated> | |||||
' This code was generated by a tool. | |||||
' Runtime Version:2.0.50727.3074 | |||||
' | |||||
' Changes to this file may cause incorrect behavior and will be lost if | |||||
' the code is regenerated. | |||||
' </auto-generated> | |||||
'------------------------------------------------------------------------------ | |||||
Option Strict On | |||||
Option Explicit On | |||||
Namespace My | |||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _ | |||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0"), _ | |||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _ | |||||
Partial Friend NotInheritable Class MySettings | |||||
Inherits Global.System.Configuration.ApplicationSettingsBase | |||||
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings) | |||||
#Region "My.Settings Auto-Save Functionality" | |||||
#If _MyType = "WindowsForms" Then | |||||
Private Shared addedHandler As Boolean | |||||
Private Shared addedHandlerLockObject As New Object | |||||
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _ | |||||
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs) | |||||
If My.Application.SaveMySettingsOnExit Then | |||||
My.Settings.Save() | |||||
End If | |||||
End Sub | |||||
#End If | |||||
#End Region | |||||
Public Shared ReadOnly Property [Default]() As MySettings | |||||
Get | |||||
#If _MyType = "WindowsForms" Then | |||||
If Not addedHandler Then | |||||
SyncLock addedHandlerLockObject | |||||
If Not addedHandler Then | |||||
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings | |||||
addedHandler = True | |||||
End If | |||||
End SyncLock | |||||
End If | |||||
#End If | |||||
Return defaultInstance | |||||
End Get | |||||
End Property | |||||
End Class | |||||
End Namespace | |||||
Namespace My | |||||
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _ | |||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _ | |||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _ | |||||
Friend Module MySettingsProperty | |||||
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _ | |||||
Friend ReadOnly Property Settings() As Global.VS2008VBSample.My.MySettings | |||||
Get | |||||
Return Global.VS2008VBSample.My.MySettings.Default | |||||
End Get | |||||
End Property | |||||
End Module | |||||
End Namespace |
<?xml version='1.0' encoding='utf-8'?> | |||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true"> | |||||
<Profiles> | |||||
<Profile Name="(Default)" /> | |||||
</Profiles> | |||||
<Settings /> | |||||
</SettingsFile> |
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProductVersion>9.0.21022</ProductVersion> | |||||
<SchemaVersion>2.0</SchemaVersion> | |||||
<ProjectGuid>{DB74E346-D064-4912-804F-342DF837388B}</ProjectGuid> | |||||
<OutputType>Exe</OutputType> | |||||
<StartupObject>VS2008VBSample.SNFMultiDLLExample</StartupObject> | |||||
<RootNamespace>VS2008VBSample</RootNamespace> | |||||
<AssemblyName>VS2008VBSample</AssemblyName> | |||||
<FileAlignment>512</FileAlignment> | |||||
<MyType>Console</MyType> | |||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> | |||||
<OptionExplicit>On</OptionExplicit> | |||||
<OptionCompare>Binary</OptionCompare> | |||||
<OptionStrict>Off</OptionStrict> | |||||
<OptionInfer>On</OptionInfer> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<DefineDebug>true</DefineDebug> | |||||
<DefineTrace>true</DefineTrace> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DocumentationFile>VS2008VBSample.xml</DocumentationFile> | |||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<DebugType>pdbonly</DebugType> | |||||
<DefineDebug>false</DefineDebug> | |||||
<DefineTrace>true</DefineTrace> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DocumentationFile>VS2008VBSample.xml</DocumentationFile> | |||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DefineDebug>true</DefineDebug> | |||||
<DefineTrace>true</DefineTrace> | |||||
<OutputPath>bin\x64\Debug\</OutputPath> | |||||
<DocumentationFile>VS2008VBSample.xml</DocumentationFile> | |||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> | |||||
<DebugType>full</DebugType> | |||||
<PlatformTarget>x64</PlatformTarget> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | |||||
<DefineTrace>true</DefineTrace> | |||||
<OutputPath>bin\x64\Release\</OutputPath> | |||||
<DocumentationFile>VS2008VBSample.xml</DocumentationFile> | |||||
<Optimize>true</Optimize> | |||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> | |||||
<DebugType>pdbonly</DebugType> | |||||
<PlatformTarget>x64</PlatformTarget> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DefineDebug>true</DefineDebug> | |||||
<DefineTrace>true</DefineTrace> | |||||
<OutputPath>bin\x86\Debug\</OutputPath> | |||||
<DocumentationFile>VS2008VBSample.xml</DocumentationFile> | |||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> | |||||
<DebugType>full</DebugType> | |||||
<PlatformTarget>x86</PlatformTarget> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | |||||
<DefineTrace>true</DefineTrace> | |||||
<OutputPath>bin\x86\Release\</OutputPath> | |||||
<DocumentationFile>VS2008VBSample.xml</DocumentationFile> | |||||
<Optimize>true</Optimize> | |||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn> | |||||
<DebugType>pdbonly</DebugType> | |||||
<PlatformTarget>x86</PlatformTarget> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="System" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Deployment" /> | |||||
<Reference Include="System.Xml" /> | |||||
<Reference Include="System.Core"> | |||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |||||
</Reference> | |||||
<Reference Include="System.Xml.Linq"> | |||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |||||
</Reference> | |||||
<Reference Include="System.Data.DataSetExtensions"> | |||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |||||
</Reference> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Import Include="Microsoft.VisualBasic" /> | |||||
<Import Include="System" /> | |||||
<Import Include="System.Collections" /> | |||||
<Import Include="System.Collections.Generic" /> | |||||
<Import Include="System.Data" /> | |||||
<Import Include="System.Diagnostics" /> | |||||
<Import Include="System.Linq" /> | |||||
<Import Include="System.Xml.Linq" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="..\..\VBSample\main.vb"> | |||||
<Link>main.vb</Link> | |||||
</Compile> | |||||
<Compile Include="My Project\AssemblyInfo.vb" /> | |||||
<Compile Include="My Project\Application.Designer.vb"> | |||||
<AutoGen>True</AutoGen> | |||||
<DependentUpon>Application.myapp</DependentUpon> | |||||
</Compile> | |||||
<Compile Include="My Project\Resources.Designer.vb"> | |||||
<AutoGen>True</AutoGen> | |||||
<DesignTime>True</DesignTime> | |||||
<DependentUpon>Resources.resx</DependentUpon> | |||||
</Compile> | |||||
<Compile Include="My Project\Settings.Designer.vb"> | |||||
<AutoGen>True</AutoGen> | |||||
<DependentUpon>Settings.settings</DependentUpon> | |||||
<DesignTimeSharedInput>True</DesignTimeSharedInput> | |||||
</Compile> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<EmbeddedResource Include="My Project\Resources.resx"> | |||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator> | |||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput> | |||||
<CustomToolNamespace>My.Resources</CustomToolNamespace> | |||||
<SubType>Designer</SubType> | |||||
</EmbeddedResource> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="My Project\Application.myapp"> | |||||
<Generator>MyApplicationCodeGenerator</Generator> | |||||
<LastGenOutput>Application.Designer.vb</LastGenOutput> | |||||
</None> | |||||
<None Include="My Project\Settings.settings"> | |||||
<Generator>SettingsSingleFileGenerator</Generator> | |||||
<CustomToolNamespace>My</CustomToolNamespace> | |||||
<LastGenOutput>Settings.Designer.vb</LastGenOutput> | |||||
</None> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> | |||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||||
Other similar extension points exist, see Microsoft.Common.targets. | |||||
<Target Name="BeforeBuild"> | |||||
</Target> | |||||
<Target Name="AfterBuild"> | |||||
</Target> | |||||
--> | |||||
</Project> |
@ECHO OFF | |||||
SETLOCAL | |||||
REM ----- Edit This Section -------- | |||||
SET SNIFFER_PATH=c:\SNF | |||||
SET AUTHENTICATION=authenticationxx | |||||
SET LICENSE_ID=licensid | |||||
REM -------------------------------- | |||||
CD /d %SNIFFER_PATH% | |||||
echo Running SNF getRulebase.cmd > getRulebase.txt | |||||
if not exist UpdateReady.txt echo No UpdateReady.txt >> getRulebase.txt | |||||
if not exist UpdateReady.txt goto DONE | |||||
REM The next line may cause trouble if your system stops while this | |||||
REM script is running. It is not needed when this script is run | |||||
REM from SNF's <update-script/> feature since only one copy will run | |||||
REM at a time. However, if you are going to run a version of this | |||||
REM script as a scheduled task you will want to uncomment the next | |||||
REM line to make sure only one copy runs at a time-- just be sure to | |||||
REM clean out any stale .lck files after a restart. | |||||
REM if exist UpdateReady.lck echo getRulebase.cmd locked/running >> getRulebase.txt | |||||
REM if exist UpdateReady.lck goto DONE | |||||
:DOWNLOAD | |||||
copy UpdateReady.txt UpdateReady.lck > nul | |||||
if exist %LICENSE_ID%.new del %LICENSE_ID%.new | |||||
echo. | |||||
curl -v "http://www.sortmonster.net/Sniffer/Updates/%LICENSE_ID%.snf" -o %LICENSE_ID%.new -s -S -R -z %LICENSE_ID%.snf -H "Accept-Encoding:gzip" --compressed -u sniffer:ki11sp8m 2>> getRulebase.txt | |||||
if %ERRORLEVEL% NEQ 0 del %LICENSE_ID%.new 2> nul | |||||
if not exist %LICENSE_ID%.new echo New rulebase file NOT downloaded >> getRulebase.txt | |||||
if not exist %LICENSE_ID%.new goto CLEANUP | |||||
snf2check.exe %LICENSE_ID%.new %AUTHENTICATION% 2>> getRulebase.txt | |||||
if errorlevel 1 goto CLEANUP | |||||
echo New rulebase file tested OK >> getRulebase.txt | |||||
if exist %LICENSE_ID%.old del %LICENSE_ID%.old | |||||
if exist %LICENSE_ID%.snf rename %LICENSE_ID%.snf %LICENSE_ID%.old | |||||
rename %LICENSE_ID%.new %LICENSE_ID%.snf | |||||
if exist UpdateReady.txt del UpdateReady.txt | |||||
if exist UpdateReady.lck del UpdateReady.lck | |||||
:CLEANUP | |||||
if exist %LICENSE_ID%.new del %LICENSE_ID%.new | |||||
if exist UpdateReady.lck del UpdateReady.lck | |||||
:DONE | |||||
echo Done >> getRulebase.txt | |||||
REM This is a good place to add a line that will email getrulebase.txt to | |||||
REM yourself so that you know what just happened. | |||||
ENDLOCAL |
<!-- Change 'licenseid' and 'xxxxxxxxxxxxxxxx' to match your license info --> | |||||
<snf><identity licenseid='licensid' authentication='authenticationxx'/></snf> | |||||
/* snfmultidll.h | |||||
// Copyright (C) 2007-2009 ARM Research Labs, LLC | |||||
// | |||||
// SNFMulti DLL header. | |||||
*/ | |||||
#ifndef snfmultidll_included | |||||
#define snfmultidll_included | |||||
const int snf_SUCCESS = 0; | |||||
const int snf_ERROR_CMD_LINE = 65; | |||||
const int snf_ERROR_LOG_FILE = 66; | |||||
const int snf_ERROR_RULE_FILE = 67; | |||||
const int snf_ERROR_RULE_DATA = 68; | |||||
const int snf_ERROR_RULE_AUTH = 73; | |||||
const int snf_ERROR_MSG_FILE = 69; | |||||
const int snf_ERROR_ALLOCATION = 70; | |||||
const int snf_ERROR_BAD_MATRIX = 71; | |||||
const int snf_ERROR_MAX_EVALS = 72; | |||||
const int snf_ERROR_UNKNOWN = 99; | |||||
const int snf_ERROR_NO_HANDLE = -1; | |||||
const int snf_ERROR_SCAN_FAILED = -2; | |||||
const int snf_ERROR_EXCEPTION = -3; | |||||
/* | |||||
enum snfIPRange { // IP action ranges | |||||
Unknown, // Unknown - not defined. | |||||
White, // This is a good guy. | |||||
Normal, // Benefit of the doubt. | |||||
New, // It is new to us. | |||||
Caution, // This is suspicious. | |||||
Black, // This is bad. | |||||
Truncate // Don't even bother looking. | |||||
}; | |||||
*/ | |||||
/* Map these C constants to the enum snfIPRange */ | |||||
const int snf_IP_Unknown = 0; | |||||
const int snf_IP_White = 1; | |||||
const int snf_IP_Normal = 2; | |||||
const int snf_IP_New = 3; | |||||
const int snf_IP_Caution = 4; | |||||
const int snf_IP_Black = 5; | |||||
const int snf_IP_Truncate = 6; | |||||
/* IP Reputation Figure Constants */ | |||||
const double snf_ReputationMehResult = 0.0; /* Don't know or don't care */ | |||||
const double snf_ReputationBadResult = 1.0; /* IP is pure evil */ | |||||
const double snf_ReputationGoodResult = -1.0; /* IP is pure good */ | |||||
/* This is the API to the SNFMulti DLL */ | |||||
#define IMP __declspec(dllimport) | |||||
extern "C" { | |||||
IMP int setThrottle(int Threads); /* Set a scan thread limit */ | |||||
IMP int startupSNF(char* Path); /* Start SNF with configuration. */ | |||||
IMP int startupSNFAuthenticated(char* Path, char* Lic, char* Auth); /* Start SNF with conf & auth. */ | |||||
IMP int shutdownSNF(); /* Shutdown SNF. */ | |||||
IMP int testIP(unsigned long int IPToCheck); /* Test the IP for a GBUdb range. */ | |||||
IMP double getIPReputation(unsigned long int IPToCheck); /* Get reputation figure for IP. */ | |||||
IMP int scanBuffer(unsigned char* Bfr, int Length, char* Name, int Setup); /* Scan msgBuffer, name, setup time. */ | |||||
IMP int scanFile(char* FilePath, int Setup); /* Scan msgFile, setup time. */ | |||||
IMP int getScanXHeaders(int ScanHandle, char** Bfr, int* Length); /* Get result & XHeaders. */ | |||||
IMP int getScanXMLLog(int ScanHandle, char** Bfr, int* Length); /* Get result & XML Log. */ | |||||
IMP int getScanClassicLog(int ScanHandle, char** Bfr, int* Length); /* Get result & Classic Log. */ | |||||
IMP int getScanResult(int ScanHandle); /* Get just the scan result. */ | |||||
IMP int closeScan(int ScanHandle); /* Close the scan result. */ | |||||
} | |||||
#endif |
<html> | |||||
<head> | |||||
<title>C:\M\Projects\MessageSniffer\PKG-SNF-SDK-WIN_Work\PKG-SNF-SDK-WIN\include\snfmultidll.h</title> | |||||
<style> | |||||
body { background-color: #ffffff; font-family: "Courier New"; font-size:10.0pt; font-style: normal; font-weight: normal; text-decoration: none; } | |||||
.se2 { color: #000000; background-color: #ffffff; } /* Window Text */ | |||||
.se17 { color: #800080; background-color: #ffffff; } /* Keyword */ | |||||
.se19 { color: #000080; background-color: #ffffff; } /* Number */ | |||||
.se20 { color: #008080; background-color: #ffffff; } /* String */ | |||||
.se21 { color: #008000; background-color: #ffffff; font-style: italic; } /* Comment */ | |||||
.se22 { color: #808000; background-color: #ffffff; } /* Preprocessor */ | |||||
.se23 { color: #800000; background-color: #ffffff; } /* Punctuation */ | |||||
.se25 { color: #000000; background-color: #ffffff; } /* Operator */ | |||||
.se28 { color: #000000; background-color: #ffffff; font-weight: bolder; } /* Function */ | |||||
.se55 { color: #000000; background-color: #ffffff; } /* Window Text */ | |||||
.se56 { color: #303080; background-color: #ffffff; } /* Number */ | |||||
</style> | |||||
</head> | |||||
<body> | |||||
<pre> | |||||
<span class="se21">/* snfmultidll.h</span> | |||||
<span class="se21">// Copyright (C) 2007-2009 ARM Research Labs, LLC</span> | |||||
<span class="se21">//</span> | |||||
<span class="se21">// SNFMulti DLL header.</span> | |||||
<span class="se21">*/</span> | |||||
<span class="se22">#ifndef</span><span class="se2"> </span><span class="se55">snfmultidll_included</span> | |||||
<span class="se22">#define</span><span class="se2"> </span><span class="se55">snfmultidll_included</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_SUCCESS</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_CMD_LINE</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">65</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_LOG_FILE</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">66</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_RULE_FILE</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">67</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_RULE_DATA</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">68</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_RULE_AUTH</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">73</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_MSG_FILE</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">69</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_ALLOCATION</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">70</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_BAD_MATRIX</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">71</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_MAX_EVALS</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">72</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_UNKNOWN</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">99</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_NO_HANDLE</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se25">-</span><span class="se19">1</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_SCAN_FAILED</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se25">-</span><span class="se19">2</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_ERROR_EXCEPTION</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se25">-</span><span class="se19">3</span><span class="se25">;</span> | |||||
<span class="se21">/*</span> | |||||
<span class="se21">enum snfIPRange { // IP action ranges</span> | |||||
<span class="se21"> Unknown, // Unknown - not defined.</span> | |||||
<span class="se21"> White, // This is a good guy.</span> | |||||
<span class="se21"> Normal, // Benefit of the doubt.</span> | |||||
<span class="se21"> New, // It is new to us.</span> | |||||
<span class="se21"> Caution, // This is suspicious.</span> | |||||
<span class="se21"> Black, // This is bad.</span> | |||||
<span class="se21"> Truncate // Don't even bother looking.</span> | |||||
<span class="se21">};</span> | |||||
<span class="se21">*/</span> | |||||
<span class="se21">/* Map these C constants to the enum snfIPRange */</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_Unknown</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">0</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_White</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">1</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_Normal</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">2</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_New</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">3</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_Caution</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">4</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_Black</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">5</span><span class="se25">;</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">snf_IP_Truncate</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se19">6</span><span class="se25">;</span> | |||||
<span class="se21">/* IP Reputation Figure Constants */</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se55">snf_ReputationMehResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se56">0.0</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Don't know or don't care */</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se55">snf_ReputationBadResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se56">1.0</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* IP is pure evil */</span> | |||||
<span class="se17">const</span><span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se55">snf_ReputationGoodResult</span><span class="se2"> </span><span class="se25">=</span><span class="se2"> </span><span class="se25">-</span><span class="se56">1.0</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* IP is pure good */</span> | |||||
<span class="se21">/* This is the API to the SNFMulti DLL */</span> | |||||
<span class="se22">#define</span><span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se28">__declspec</span><span class="se2">(</span><span class="se55">dllimport</span><span class="se2">)</span> | |||||
<span class="se17">extern</span><span class="se2"> </span><span class="se20">"C"</span><span class="se2"> </span><span class="se23">{</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">setThrottle</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">Threads</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Set a scan thread limit */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">startupSNF</span><span class="se2">(</span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Path</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Start SNF with configuration. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">startupSNFAuthenticated</span><span class="se2">(</span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Path</span><span class="se2">, </span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Lic</span><span class="se2">, </span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Auth</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Start SNF with conf & auth. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">shutdownSNF</span><span class="se2">()</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Shutdown SNF. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">testIP</span><span class="se2">(</span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">long</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">IPToCheck</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Test the IP for a GBUdb range. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">double</span><span class="se2"> </span><span class="se28">getIPReputation</span><span class="se2">(</span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">long</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se55">IPToCheck</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Get reputation figure for IP. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">scanBuffer</span><span class="se2">(</span><span class="se17">unsigned</span><span class="se2"> </span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">, </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">, </span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Name</span><span class="se2">, </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Setup</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Scan msgBuffer, name, setup time. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">scanFile</span><span class="se2">(</span><span class="se17">char</span><span class="se25">*</span><span class="se2"> </span><span class="se55">FilePath</span><span class="se2">, </span><span class="se17">int</span><span class="se2"> </span><span class="se55">Setup</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Scan msgFile, setup time. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanXHeaders</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">, </span><span class="se17">char</span><span class="se25">**</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">, </span><span class="se17">int</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Get result & XHeaders. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanXMLLog</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">, </span><span class="se17">char</span><span class="se25">**</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">, </span><span class="se17">int</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Get result & XML Log. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanClassicLog</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">, </span><span class="se17">char</span><span class="se25">**</span><span class="se2"> </span><span class="se55">Bfr</span><span class="se2">, </span><span class="se17">int</span><span class="se25">*</span><span class="se2"> </span><span class="se55">Length</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Get result & Classic Log. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">getScanResult</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Get just the scan result. */</span> | |||||
<span class="se2"> </span><span class="se55">IMP</span><span class="se2"> </span><span class="se17">int</span><span class="se2"> </span><span class="se28">closeScan</span><span class="se2">(</span><span class="se17">int</span><span class="se2"> </span><span class="se55">ScanHandle</span><span class="se2">)</span><span class="se25">;</span><span class="se2"> </span><span class="se21">/* Close the scan result. */</span> | |||||
<span class="se23">}</span> | |||||
<span class="se22">#endif</span> | |||||
</pre> | |||||
</body> | |||||
</html> |
<!-- SNFMulti V3.0 Configuration File, Setup: Typical of Win* Client / Server --> | |||||
<!-- http://www.armresearch.com/support/articles/software/snfServer/config/snfEngine.jsp --> | |||||
<snf> | |||||
<node identity='c:/SNF/identity.xml'> | |||||
<paths> | |||||
<log path='c:/SNF/'/> | |||||
<rulebase path='c:/SNF/'/> | |||||
<workspace path='c:/SNF/'/> | |||||
</paths> | |||||
<logs> | |||||
<rotation localtime='no'/> | |||||
<status> | |||||
<second log='yes' append='no'/> | |||||
<minute log='yes' append='no'/> | |||||
<hour log='no' append='no'/> | |||||
</status> | |||||
<scan> | |||||
<identifier force-message-id='no'/> | |||||
<classic mode='none' rotate='yes' matches='unique'/> | |||||
<xml mode='file' rotate='yes' matches='all' performance='yes' gbudb='yes'/> | |||||
<xheaders> | |||||
<output mode='none'/> | |||||
<version on-off='off'>X-MessageSniffer-Version</version> | |||||
<license on-off='off'>X-MessageSniffer-License</license> | |||||
<rulebase on-off='off'>X-MessageSniffer-RulebaseUTC</rulebase> | |||||
<identifier on-off='off'>X-MessageSniffer-Identifier</identifier> | |||||
<gbudb on-off='on'>X-GBUdb-Analysis</gbudb> | |||||
<result on-off='off'>X-MessageSniffer-Scan-Result</result> | |||||
<matches on-off='on'>X-MessageSniffer-Rules</matches> | |||||
<black on-off='off'>X-MessageSniffer-Spam: Yes</black> | |||||
<white on-off='off'>X-MessageSniffer-White: Yes</white> | |||||
<clean on-off='off'>X-MessageSniffer-Clean: Yes</clean> | |||||
<symbol on-off='off' n='0'>X-MessageSniffer-SNF-Group: OK</symbol> | |||||
<symbol on-off='off' n='20'>X-MessageSniffer-SNF-Group: Truncated</symbol> | |||||
<symbol on-off='off' n='40'>X-MessageSniffer-SNF-Group: Caution</symbol> | |||||
<symbol on-off='off' n='63'>X-MessageSniffer-SNF-Group: Black</symbol> | |||||
<symbol on-off='off' n='62'>X-MessageSniffer-SNF-Group: Obfuscation</symbol> | |||||
<symbol on-off='off' n='61'>X-MessageSniffer-SNF-Group: Abstract</symbol> | |||||
<symbol on-off='off' n='60'>X-MessageSniffer-SNF-Group: General</symbol> | |||||
<symbol on-off='off' n='59'>X-MessageSniffer-SNF-Group: Casinos-Gambling</symbol> | |||||
<symbol on-off='off' n='58'>X-MessageSniffer-SNF-Group: Debt-Credit</symbol> | |||||
<symbol on-off='off' n='57'>X-MessageSniffer-SNF-Group: Get-Rich</symbol> | |||||
<symbol on-off='off' n='56'>X-MessageSniffer-SNF-Group: Ink-Toner</symbol> | |||||
<symbol on-off='off' n='55'>X-MessageSniffer-SNF-Group: Malware</symbol> | |||||
<symbol on-off='off' n='54'>X-MessageSniffer-SNF-Group: Porn-Dating-Adult</symbol> | |||||
<symbol on-off='off' n='53'>X-MessageSniffer-SNF-Group: Scam-Phishing</symbol> | |||||
<symbol on-off='off' n='52'>X-MessageSniffer-SNF-Group: Snake-Oil</symbol> | |||||
<symbol on-off='off' n='51'>X-MessageSniffer-SNF-Group: Spamware</symbol> | |||||
<symbol on-off='off' n='50'>X-MessageSniffer-SNF-Group: Media-Theft</symbol> | |||||
<symbol on-off='off' n='49'>X-MessageSniffer-SNF-Group: AV-Push</symbol> | |||||
<symbol on-off='off' n='48'>X-MessageSniffer-SNF-Group: Insurance</symbol> | |||||
<symbol on-off='off' n='47'>X-MessageSniffer-SNF-Group: Travel</symbol> | |||||
</xheaders> | |||||
</scan> | |||||
</logs> | |||||
<network> | |||||
<sync secs='30' host='sync.messagesniffer.net' port='25'/> | |||||
<update-script on-off='on' call='c:/SNF/getRulebase.cmd' guard-time='180'/> | |||||
</network> | |||||
<xci on-off='on' port='9001'/> | |||||
<gbudb> | |||||
<database> | |||||
<condense minimum-seconds-between='600'> | |||||
<time-trigger on-off='on' seconds='86400'/> | |||||
<posts-trigger on-off='off' posts='1200000'/> | |||||
<records-trigger on-off='off' records='600000'/> | |||||
<size-trigger on-off='on' megabytes='150'/> | |||||
</condense> | |||||
<checkpoint on-off='on' secs='3600'/> | |||||
</database> | |||||
<regions> | |||||
<white on-off='on' symbol='0'> | |||||
<edge probability='-1.0' confidence='0.4'/> | |||||
<edge probability='-0.8' confidence='1.0'/> | |||||
<panic on-off='on' rule-range='1000'/> | |||||
</white> | |||||
<caution on-off='on' symbol='40'> | |||||
<edge probability='0.4' confidence='0.0'/> | |||||
<edge probability='0.8' confidence='0.5'/> | |||||
</caution> | |||||
<black on-off='on' symbol='63'> | |||||
<edge probability='0.8' confidence='0.2'/> | |||||
<edge probability='0.8' confidence='1.0'/> | |||||
<truncate on-off='on' probability='0.9' peek-one-in='5' symbol='20'/> | |||||
<sample on-off='on' probability='0.8' grab-one-in='5' passthrough='no' passthrough-symbol='0'/> | |||||
</black> | |||||
</regions> | |||||
<training on-off='on'> | |||||
<bypass> | |||||
<!-- <header name='To:' find='spam@example.com'/> --> | |||||
<!-- <header name='Received:' ordinal='1' find='friendlyhost.com'/> --> | |||||
</bypass> | |||||
<drilldown> | |||||
<!-- <received ordinal='0' find='[12.34.56.'/> where we want to ignore 12.34.56.0/24 --> | |||||
<!-- <received ordinal='0' find='mixed-source.com'/> --> | |||||
<!-- <received ordinal='1' find='mixed-source-internal.com'/> --> | |||||
</drilldown> | |||||
<source> | |||||
<!-- <header name='X-Use-This-Source:' received='mixedsource.com [' ordinal='0' /> --> | |||||
<!-- <header name='X-Originating-IP:' received='hotmail.com [' ordinal='0' /> --> | |||||
</source> | |||||
<white> | |||||
<result code='1'/> | |||||
<!-- <header name='Received:' ordinal='0' find='.friendlyhost.com'/> --> | |||||
</white> | |||||
</training> | |||||
</gbudb> | |||||
<rule-panics> | |||||
<!-- | |||||
<rule id='123456'/> | |||||
<rule id='123457'/> | |||||
--> | |||||
</rule-panics> | |||||
<platform/> | |||||
<msg-file type='rfc822'/> | |||||
</node> | |||||
</snf> | |||||
<!-- SNF Xml Command Interface Examples --> | |||||
<!-- Scanner --> | |||||
<snf><xci><scanner><scan file='filepath'/></scanner></xci></snf> | |||||
<snf><xci><scanner><result code='63'/></scanner></xci></snf> | |||||
<snf><xci><scanner><scan file='filepath' xhdr='yes' log='no' ip='12.34.56.78'/></scanner></xci></snf> | |||||
<snf><xci><scanner><result code='63'><xhdr> | |||||
X-Signature-Violations: | |||||
57-1404199-965-976-m | |||||
57-1404199-1352-1363-m | |||||
57-1404199-965-976-f | |||||
</xhdr></result></scanner></xci></snf> | |||||
<!-- GBUdb --> | |||||
<snf><xci><gbudb><set ip='12.34.56.78' type='good'/></gbudb></xci></snf> <!-- Set flag to good on ip --> | |||||
<snf><xci><gbudb><set ip='12.34.56.78' type='bad'/></gbudb></xci></snf> <!-- Set flag to bad on ip --> | |||||
<snf><xci><gbudb><set ip='12.34.56.78' type='ugly'/></gbudb></xci></snf> <!-- Set flag to ugly on ip --> | |||||
<snf><xci><gbudb><set ip='12.34.56.78' type='ignore'/></gbudb></xci></snf> <!-- Set flag to ignore on ip --> | |||||
<snf><xci><gbudb><set ip='12.34.56.78' type='ugly' b='1' g='0'/></gbudb></xci></snf> <!-- Set flag and counts on ip --> | |||||
<snf><xci><gbudb><good ip='12.34.56.78'/></gbudb></xci></snf> <!-- Record a "good" event on ip --> | |||||
<snf><xci><gbudb><bad ip='12.34.56.78'/></gbudb></xci></snf> <!-- Record a "bad" event on ip --> | |||||
<snf><xci><gbudb><test ip='12.34.56.78'/></gbudb></xci></snf> <!-- Return the state of ip --> | |||||
<snf><xci><gbudb><drop ip='12.34.56.78'/></gbudb></xci></snf> <!-- Forget the IP --> | |||||
<!-- GBUdb Result, always --> | |||||
<snf><xci><gbudb><result ip='12.34.56.78' type='ugly' p='1.0' c='0.001' b='1' g='0' range='caution' code='40'/></gbudb></xci></snf> | |||||
<!-- status report request --> | |||||
<snf><xci><report><request><status class='second'/></request></report></xci></snf> | |||||
<!-- status report result --> | |||||
<snf><xci><report><response><!-- actual status report --></response></report></xcl></snf> | |||||
<!-- Server --> | |||||
<snf><xci><server><command command='shutdown'/></server></xci></snf> | |||||
<snf><xci><server><response message='shutdown in progress' code='0'/></server></xci></snf> | |||||
<!-- Specialized Server Requests --> | |||||
<snf><xci><server><command command='systemdefinedcommand'> | |||||
<system-defined/><command/><elements/> | |||||
</command></server></xci></snf> | |||||
<snf><xci><server><response message='shutdown in progress' code='0'> | |||||
<system-defined/><response/><elements/> | |||||
</response></server></xci></snf> | |||||
<!-- XCI Error Response --> | |||||
<snf><xci><error message="What was that?"/></xci></snf> | |||||
' Location of SNFMulti.dll. | ' Location of SNFMulti.dll. | ||||
'Const SNFMULTI_DLL As String = "..\..\..\..\64bitDll\SNFMulti.dll" ' Set CPU type to "Any CPU" | 'Const SNFMULTI_DLL As String = "..\..\..\..\64bitDll\SNFMulti.dll" ' Set CPU type to "Any CPU" | ||||
Const SNFMULTI_DLL As String = "..\..\..\..\..\64bitDll\SNFMulti.dll" ' Set CPU type to "x64" | |||||
'Const SNFMULTI_DLL As String = "..\..\..\..\..\32bitDll\SNFMulti.dll" ' Set CPU type to "x86" | |||||
'Const SNFMULTI_DLL As String = "..\..\..\..\..\64bitDll\SNFMulti.dll" ' Set CPU type to "x64" | |||||
Const SNFMULTI_DLL As String = "..\..\..\..\..\32bitDll\SNFMulti.dll" ' Set CPU type to "x86" | |||||
'int setThrottle(int Threads); /* Set scan thread limit. */ | 'int setThrottle(int Threads); /* Set scan thread limit. */ | ||||
'int startupSNF(char* Path); /* Start SNF with configuration. */ | 'int startupSNF(char* Path); /* Start SNF with configuration. */ |
5) Follow the directions in each directorie's README file. | 5) Follow the directions in each directorie's README file. | ||||
To build and test the SDK: | |||||
1) In PKG-SNF-SDK-WIN/trunk/MinGW-32: | |||||
a) compileSNFMultiDLL.cmd. | |||||
b) buildSNFMultiDLL.cmd. | |||||
c) buildSNFMultiTestDLL.cmd. | |||||
d) buildvs2008SNFMultiImportLib.cmd (in vs2008 command prompt). | |||||
e) SNFMultiTest.exe. | |||||
f) installSNFMultiLibrary.cmd. | |||||
2) Repeat in MinGW-64. | |||||
3) Build and run VS2008CPPSample, x32 and x64. First copy | |||||
snf_engine.xml to VS2008CPPSample. Needed to copy *.dll to | |||||
VS2008CPPSample. | |||||
4) Build and run VS2008CSSample, any, x32, and x64. First copy | |||||
snf_engine.xml to VS2008CSSample. | |||||
5) Build and run VS2008VBSample, any, x32, and x64. First copy | |||||
snf_engine.xml to VS2008VBSample. | |||||
To create a zipfile distribution: | To create a zipfile distribution: | ||||
1) Install jZip. | 1) Install jZip. |