Quellcode durchsuchen

CodeDweller should be external, cleaning up.

git-svn-id: https://svn.microneil.com/svn/PKG-SNF-SDK-WIN/trunk@9 7d91e7c8-5a61-404e-b06a-95855fde9112
master
madscientist vor 13 Jahren
Ursprung
Commit
f5c712de06

+ 0
- 386
CodeDweller/ChangeLog Datei anzeigen

@@ -1,386 +0,0 @@
2009-05-27 Alban Deniz <adeniz@skidmark.localdomain>

* Makefile.am: Include Makefile.am and ChangeLog in the
distribution.

2009-05-23 Alban Deniz <adeniz@skidmark.localdomain>

* Makefile.am (noinst_HEADERS): Added faults.hpp and
mangler.hpp.
(libCodeDweller_a_SOURCES): Added mangler.cpp.

SNF Command Line & SNFMulti Engine / Client Change Log
------------------------------------------------------------------------------

20080710 - Version 3.0.1

Minor change to SNFServer main.cpp:59 - removed cast to (int) which caused
a precision loss error when compiling on 64 bit systems. This changes the
thread pointer info in debug mode slightly (better).

20080626 - Version 3.0, It's official.

Changed build information.
Removed extraneous comments from configuration file.

20080524 - Version V2-9rc2.25.7

Optimized networking library for additional speed & stability by moving
receive buffer allocation from heap to stack (automatic).

Optimized timing parameters in SNFClient for improved speed. Polling dealys
are now reduced to 10ms from 30ms.

Removed speed-bug in SNFClient, 100ms guard time between retries was always
executed after an attempt (even a successful attempt). The guard time is now
condition and only fires on unsuccessful attempts.

Updated XCI server logic to ensure non-blocking sockets for clients in all
socket implementations.

20080424 - Version V2-9rc2.24.6

Refactored snfScanData.clear() to reduce heap work and fragments.

Added mutex to scanMessageFile() entry point just in case some app attempts to
put multiple threads through a single engine handler. scanMessage() is already
protected and fully wraped by the new scanMessageFile() mutex.

Added non-specific runtime exception handling to XHDR injection code.

Added 2 retries w/ 300ms delay to remove original message in XHDR inject code.
If remove fails after 3 attempts the injector throws.

Added 2 retries w/ 300ms delay to rename temp file to msg in XHDR inject code.
If rename fails after 3 attempts the injector throws.

20080416 - Version V2-9rc2.23.6

Fixed bug where SNCY open() would fail on some Win* platforms with
WSAEINVAL instead of the standard EINPROGRESS or EALREADY which were expected.
Also added WSAEWOULDBLOCK to cover other "ambiguities" in windows sockets
implementations. InProgress() on Win* now test for any of:

WSAEINPROGRESS, WSAEALREADY, WSAEWOULDBLOCK, WSAEINVAL

20080413 - Version V2-9rc2.22.6

Fixed bug in TCPHost.open() where EALREADY was not counted as a version of
EINPROGRESS. This would cause open() to throw an unnecessary exception when
an open() required extra time.

20080413 - Version V2-9rc2.21.6

Extended timeout for SYNC session open() to the full session length. This way
if a session takes a long time to open it still has a shot at success.

20080411 - Version V2-9rc2.20.6

Adjusted snfNETmgr to use non-blocking open in SYNC sessions. Open timeout
is 1/3 of the session timeout. Session timeout is 2 * Session pacing. Open
polling uses golden spiral delay from 10ms to 340ms.

20080410 - Version V2-9rc2.19.6

Adjusted XCI manager to use new snfCFGPacket paradigm in checkCFG().

Adjusted snf_RulebaseHandler::addRulePanic() to use MyMutex and eliminated
the AutoPanicMutex and waiting scheme.

Refactored scanMessage() to use a ScopeMutex() rather than lock()/unlock().

Refactored scanMessage() to use MyCFGPacket.isRulePanic() test.

Redesigned snfCFGPacket handling to automate grab() / drop() functions.

Fixed lock-up bug: Redesigned AutoPanic posting and checking mechanisms to
eliminate potential dead-lock condition. Under some conditions a precisely
timed auto-panic posting could cause the RulebaseHandler mutex and the
AutoPanicMutex to become intertwined leading to a cascading deadlock. When
this occurred all XCI processing threads and eventually the XCI listener
thread would become blocked waiting to get the current configuration.

20080409 - Version V2-9rc2.18.6

Enhanced XCI exception handling and logging to provide additional detail.

Added code to explicitely check for zero length files in scanMessagFile().
Previously a zero length file would cause the CBFR module of the filter
chain to throw an invalid buffer exception. Now if the message file is empty
scanMessageFile() will throw a FileError stating FileEmpty!.

20080407 - Version V2-9rc2.17.6

Enhanced exception reporting in snfXCImrg


20080405 - SNFServer V2-9rc2.16.6

Reduced safetly limits on status reports to 100K for status reports and 100K
for samples. Previous values were 10M. Most full sessions from the busiest
systems are < 50K total.

Recoded sendDataTimeout() to break uploads into 512 byte chunks and insert
delays only when a chunk is fragmented. This methodology improves reliability
on Win* systems without any significant penalty on systems that don't need
socket sends() to be in smaller chunks.

Fixed TCPClient::transmit() and TCPHost::transmit() bug where returned byte
count might be -1. Now returned byte counts can only be 0 or more.

20080403 - SNFServer V2-9rc2.15.5

Minor modifications to networking module to better support non-blocking open()

Updated SNFClient with new timing and non-blocking open(). Worst case return
time from SNFClient estimated at 200 seconds (theoretically impossible). No-
connection return time from SNFClient estimated at 20 seconds.

20080326 - SNFServer V2-9rc2.15.4

Refactored snfNETmgr::sync() to consolidate non-blocking io routines.

Added detailed thread status data to XCI listener thread.

Fixed minor bug in main (not changing revision), Debug flag for internal use
was left on in the last build cycle. It is commented out now.

20080325 - SNFServer V2-9rc2.14.4

Updated snfNETmgr with comprehensive thread status data.

Refactored snfNETmgr::sync() to check a Timeout, removed TCPWatchdog.

20080325 - SNFServer V2-9rc2.13.4

Upgraded TCPWatcher code to use new threading features (type, status).

20080324 - SNFServer v2-9rc2.12.4

Added a "Rulebase Getter" feature as part of the snf_Reloader. When enabled
the Rulebase Getter will launch a user defineable system() call whenever a
new rulebase file is available. The call will be repeated until the condition
is cleared by a successful update of the rulebase file. The Rulebase Getter
will wait a configurable "guard time" between attempts. The default system()
call is "getRulebase" with a guard time of 3 minutes. In most cases this will
launch the provided getRulebase script which should be present in the start
location of SNFServer on most systems. Best practice is to configure the full
path to the update script. The system() call is made in a separate thread so
that if the system() call hangs for some reason only the Rulebase Getter is
stuck.

Built thread monitoring function for SNFServer.exe (Full status report / sec).
The thread monitoring report is turned on when the program is renamed to
SNFDebugServer.exe or if "debug" appears in the file path to the program.

Refactored XCI channels to leverage new thread monitoring.

Refactored Threading to eliminate inline code.

Improved exception handling/reporting in scanMessageFile().

Updated scanMessagFile() header injection code to accommodate messages with
no body. Previous version would throw an exception when it could not find an
injection point. The new version makes the injection point byte 0 and puts
the injected headers at the top of the message using it's best guess about the
type of line endings (CRLF or LF) to use.

Updated Threading library to include high level thread state tracking and
naming. Also creates a global Threads object that can produce a real-time
status report on all threads.

Updated Networking library to use SO_REUSEADDR by default on listeners.

20080318 - SNF2-9rc1.11.exe Consolidated several mods/fixes

Corrected scan error logging bug. Was posting <s/> now posts <e/>.

Updated scan error logging to be more uniform with non-scan errors.

Developed various script prototypes for postfix integration & automated
updates on win* systems using the new UpdateReady.txt file mechanism.

Fixed a bug in scanMessageFile() where an \n\n style insertion point
would never be detected.

Modified scanMessageFile() header injection to strip <CR> from line ends
when the message file provided does not use them. The line-end style of
the message file is detected while locating the insertion point. If the
insertion point (first blank line) does not use <CR><LF> then the SNF
generated X-Headers are stripped of <CR> in a tight loop before injection.

Enhanced error and exception reporting in SNFMulti.cpp scanMessageFile().

Enhanced exception handling in networking module. All exceptions now
throw descriptive runtime_error exceptions.

20080306 - SNF2-9rc1.8.exe (FIRST RELEASE CANDIDATE for VERSION 3!)

Added Drilldown Header Directive Functions - When the candidate source IP
comes from a header matching a drilldown directive the IP is marked "Ignore"
in GBUdb and the candidate is no longer eligible to be the source for that
message. This allows SNF to follow the trusted chain of devices (by IP) down
to the actual source of the message. It is handy for ignoring net blocks
because it can match partial IPs but it is designed to allow SNF to learn
it's way through the servers at large ISPs so that the original source for
each message can be evaluated directly.

Added Source Header Directive Functions - This feature allows SNF to acquire
the source IP for a message from a specific header rather than searching
through the Received headers in the message. This is useful when the original
source for a message is not represented in Received headers. For example:
Hotmail places the originating source IP in a special header and does not
provide a Received header for that IP. This feature is protected from abuse
by a "Context" feature which only activates the source header directive when
specific content is found in a specific received header. Using the above
example, this feature can be configured so that a Hotmail source header would
only be read if the top Recieved header contained "hotmail.com [" indicating
that the ptr lookup for the header matched the hotmail domain. Note: When a
source is pulled from a header directive that source is put into a synthetic
Received header and injected into the scanning stream (not the message) as
the first Received header.

Added forced source IP to XCI - It is now possible to "inject" or "force"
the source IP for any message by providing that IP in the XCI request or
directly in a scan...() function call. This allows the calling application
to provide the source IP for a message ahead of any Received headers that
might be in the message. This is useful when the calling application knows
the original source IP for the message but that IP is not represented in
the Received headers and it is not desireable to use the Source Header
Directive mechanism.

Added forced source IP mode to SNFClient - It is now possible to call the
SNFClient utility with an IP4Address using the syntax:

SNFClient -source=12.34.56.78

The -source mode of SNFClient exercises the forced source IP feature in
the XCI (see above)

Added Status Report features to SNFClient and XCI - It is now possible to
request the latest status.second, status.minute, or status.hour data via
the XCI and SNFClient. The syntax for requesting a status report using the
SNFClient is:

SNFClient -status.second
SNFClient -status.minute
SNFClient -status.hour

In addition to providing status reports the SNFClient in this mode will
return a nonzero value (usually 99) if it is unable to get a status report
from SNFServer. This feature can be used to verify that SNFServer is up
and responding. If SNFServer is OK then the result code returned is 0.

Added result codes to SNFClient -test and XCI IP test functions - The XCI
engine has been upgraded to provide the range value for the IP under test
as well as the symbolic result code associated with that range. This allows
the -test function to provide results that are consistent with the GBUdb
configuration without additional processing: For example, if the IP falls
in the Caution range then the Caution result code will be returned just
as if a message had been scanned with the same IP and no pattern match
occurred. The same is true for Truncate and Black range hits.

Added Timestamp and Command Line Parameter data to SNFClient.exe.err - When
an error occurs with SNFClient that may not appear in the SNFServer logs an
entry is appended to the SNFClient.exe.err file. That in itself is not new.
The new feature is that the entries added to the SNFClient.exe.err file now
include timestamp and command line data to aid in debugging.

Added BIG-ENDIAN Conversion - When the SNFServer program is compiled on a
system that uses a BIG-ENDIAN processor (such as a power-mac) the rulebase
load process now includes a routine to convert the token matrix from it's
native LITTLE-ENDIAN format to a BIG-ENDIAN format. This solves a bug where
Power-Mac (and presumably other BIG-ENDIAN systems) could compile and run
the SNF* software but were unable to capture spam because the token matrix
in the rulebase file was misinterpreted.

Note: The BIG-ENDIAN Conversion feature is still considered experimental
because it has not yet been thoroughly tested.

Updated the Configuration Log to include all of the current configuration
features and to improve it's readability.


20080207 - SNF2-9b1.7.exe

SYNC Timeout now 2x SYNC Schedule

SNFServer now produces an UpdateReady.txt file when the UTC timestamp on
the SYNC server is newer than the UTC timestamp of the active rulebase. It
is presumed that a suitable update script or program will run periodically
and download a fresh rulebase file if the UpdateReady.txt file is present.
The update script should remove the UpdateReady.txt file when it completes
a successful download of the new rulebase file.

Added available rulebase UTC in status reports <udate utc.../>

Added Automatic path fixup for ending / or \

Added option to use local time in log rotation <rotation localtime='no'/>
The default is still utc.

20071102 - SNF2-9b1.6.exe

Increased MAX_EVALS from 1024 to 2048.

Adjusted defult range envelopes in snf_engine.xml to be more conservative.

20071017 - SNF2-9b1.5.exe

Added a missing #include directive to the networking.hpp file. The
missing #include was not a factor on Linux and Windows systems but
caused compiler errors on BSD systems.

Corrected a bug in the GBUdb White Range code where any message with a
white range source IP was being forced to the white result code. The
engine now (correctly) only forces the result and records the event when
a black pattern rule was matched and the White Range IP causes that
scan result to be overturned. If the scan result was not a black pattern
match then the original scan result is allowed to pass through.

Corrected a bug in the Header Analysis filter chain module that would
cause the first header in the message to be ignored in some cases.

Corrected an XML log format problem so that <s/> elements are correctly
open ended <s ....> or closed (empty) <s..../> according to whether they
have subordinate elements.

Adjusted the GBUdb header info format. The order of the Confidence
figure and Probabilty figure is now the same as in the XML log files
(C then P). The confidence and probability figures are now preceeded
with c= and p= respectively so that it's easy to tell which is which.

20071009 - SNF2-9b1.4.exe

Tightened up the XCI handler code and removed the watchdog. The watchdog
would restart the listener if there were no connections in 5 minutes. It
was originally added to provide additional stability, however in practice
there have been no "stalled listeners". Also, a stalled listener would
likely be a sign of a different problem that the watchdog would tend to
hide.

Modified and refactored the XCI configuration management code. All XCI config
changes and up-down operations are now handled in a single function except
upon exit from the main XCI thread where XCI_shutdown() is always called.

Added some more detailed exception handling code to the XCI component so that
more data will be logged in the event of an error.


20071008 - SNF2-9b1.2.exe

Added support for passing Communigate Message Files directly. Communigate adds
data to the top of the message file. That data stops at the first blank line and
the rfc822 message begins. The SNFServer engine can now be told to ignore this
extra data using the following option:

<msg-file type='cgp'/> <!-- type='cgp' for communigate message files -->

If the msg-file type is anything other than 'cgp' then it will treat the message
file as a standard rfc822 message in the usual way. The default setting is

<msg-file type='rfc822'/>





+ 0
- 41
CodeDweller/Makefile.am Datei anzeigen

@@ -1,41 +0,0 @@
## Process this file with automake to produce Makefile.in
##
## $Id$
##
##
## Author: Alban Deniz
##
## Copyright (C) 2008 by MicroNeil Corporation. All rights reserved.
##

CXXFLAGS = $(SNF_CXXFLAGS)

noinst_LIBRARIES = \
libCodeDweller.a

libCodeDweller_a_SOURCES = \
@top_srcdir@/CodeDweller/base64codec.cpp \
@top_srcdir@/CodeDweller/configuration.cpp \
@top_srcdir@/CodeDweller/networking.cpp \
@top_srcdir@/CodeDweller/threading.cpp \
@top_srcdir@/CodeDweller/mangler.cpp \
@top_srcdir@/CodeDweller/timing.cpp

noinst_HEADERS = \
@top_srcdir@/CodeDweller/base64codec.hpp \
@top_srcdir@/CodeDweller/configuration.hpp \
@top_srcdir@/CodeDweller/configuration.inline.hpp \
@top_srcdir@/CodeDweller/histogram.hpp \
@top_srcdir@/CodeDweller/networking.hpp \
@top_srcdir@/CodeDweller/networking.inline.hpp \
@top_srcdir@/CodeDweller/threading.hpp \
@top_srcdir@/CodeDweller/faults.hpp \
@top_srcdir@/CodeDweller/mangler.hpp \
@top_srcdir@/CodeDweller/timing.hpp

EXTRA_DIST = \
Makefile.am \
ChangeLog

clean-local:
rm -f *.gcno *.gcov *.gcda *~

+ 0
- 276
CodeDweller/base64codec.cpp Datei anzeigen

@@ -1,276 +0,0 @@
// 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;
}


+ 0
- 49
CodeDweller/base64codec.hpp Datei anzeigen

@@ -1,49 +0,0 @@
// 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

+ 0
- 1242
CodeDweller/configuration.cpp
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 0
- 734
CodeDweller/configuration.hpp Datei anzeigen

@@ -1,734 +0,0 @@
// 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


+ 0
- 576
CodeDweller/configuration.inline.hpp Datei anzeigen

@@ -1,576 +0,0 @@
// 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;
}

+ 0
- 173
CodeDweller/faults.hpp Datei anzeigen

@@ -1,173 +0,0 @@
// 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 =========================================

+ 0
- 60
CodeDweller/histogram.hpp Datei anzeigen

@@ -1,60 +0,0 @@
// 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


+ 0
- 106
CodeDweller/mangler.cpp Datei anzeigen

@@ -1,106 +0,0 @@
// 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.
}



+ 0
- 34
CodeDweller/mangler.hpp Datei anzeigen

@@ -1,34 +0,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


+ 0
- 682
CodeDweller/networking.cpp Datei anzeigen

@@ -1,682 +0,0 @@
// 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.
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("TCPClient::transmit() NULL Bfr!");
if(0 > size) // Watch out for bad sizes.
throw Networking::SocketWriteError("TCPClient::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 send - return.
} else { // If this was a different kind of error
throw Networking::SocketWriteError( // then throw!
Network.DescriptiveError(
"TCPClient::transmit().send()", LastError));
}
}
return ByteCount; // Ultimately return the 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
////////////////////////////////////////////////////////////////////////////////

+ 0
- 539
CodeDweller/networking.hpp Datei anzeigen

@@ -1,539 +0,0 @@
// 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(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...

+ 0
- 373
CodeDweller/networking.inline.hpp Datei anzeigen

@@ -1,373 +0,0 @@
// 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) || (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(isOpen()) close(); // any open socket is closed.
}

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
if(isOpen()) close(); // Close when being destroyed.
}

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
if(isOpen()) close(); // Close when being destroyed.
}

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() { // Close when deleting.
close();
}

+ 0
- 472
CodeDweller/threading.cpp Datei anzeigen

@@ -1,472 +0,0 @@
// 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
////////////////////////////////////////////////////////////////////////////////

+ 0
- 485
CodeDweller/threading.hpp Datei anzeigen

@@ -1,485 +0,0 @@
// 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 ======================================

+ 0
- 328
CodeDweller/timing.cpp Datei anzeigen

@@ -1,328 +0,0 @@
// 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 //////////////////////////////////////////////////

#ifdef WIN32
#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 ////////////////////////////////////////////

#ifdef WIN32

// 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.
}

+ 0
- 360
CodeDweller/timing.hpp Datei anzeigen

@@ -1,360 +0,0 @@
// 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.

Laden…
Abbrechen
Speichern