//// Platform Specific Stuff /////////////////////////////////////////////////// | //// Platform Specific Stuff /////////////////////////////////////////////////// | ||||
#if defined(WIN32) || defined(WIN64) | #if defined(WIN32) || defined(WIN64) | ||||
#include "winerror.h" | |||||
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
//// Being Windows specific code | //// Being Windows specific code | ||||
return NULL; // non blocking mode so we return | return NULL; // non blocking mode so we return | ||||
} // NULL when we see them. | } // NULL when we see them. | ||||
} | } | ||||
// Set SO_NOSIGPIPE if needed | |||||
// Set SO_NOSIGPIPE if needed | if( // On some systems we may have to | ||||
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
if( // On some systems we may have to | 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | ||||
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. | ||||
int TurnedOn = 1; // Prepare to turn this option on. | setsockopt( | ||||
int result = // Set SO_NOSIGPIPE. | NewHandle, | ||||
setsockopt( | SOL_SOCKET, | ||||
NewHandle, | SO_NOSIGPIPE, | ||||
SOL_SOCKET, | (char*) &TurnedOn, | ||||
SO_NOSIGPIPE, | sizeof(TurnedOn)); | ||||
(char*) &TurnedOn, | if(0 > result) { // If there was an error then | ||||
sizeof(TurnedOn)); | LastError = Network.getLastError(); // Capture the error information | ||||
Network.closeSocket(NewHandle); // close the handle (avoid leaks) | |||||
if(0 > result) { // If there was an error then | throw Networking::SocketSetSockOptError( // and throw a descriptive exception. | ||||
LastError = Network.getLastError(); // Capture the error information | Network.DescriptiveError( | ||||
Network.closeSocket(NewHandle); // close the handle (avoid leaks) | "TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError)); | ||||
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. | // If things have gone well we can do what we came for. | ||||
if(0 > size) // Watch out for bad sizes. | if(0 > size) // Watch out for bad sizes. | ||||
throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!"); | throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!"); | ||||
LastError = 0; // No errors yet. | LastError = 0; // No errors yet. | ||||
int ByteCount = 0; // No bytes sent yet this pass. | int ByteCount = 0; // No bytes sent yet this pass. | ||||
ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. | ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. | ||||
LastError = Network.getLastError(); // Grab any error code. | LastError = Network.getLastError(); // Grab any error code. | ||||
bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred. | |||||
bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred. | const int NoBytesSent = 0; // This is our "Would Block" result. | ||||
const int NoBytesSent = 0; // This is our "Would Block" result. | |||||
if(AnErrorOccurred) { // If there was an error check it out. | if(AnErrorOccurred) { // If there was an error check it out. | ||||
if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then | if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then | ||||
return NoBytesSent; // return no bytes sent (try again). | return NoBytesSent; // return no bytes sent (try again). | ||||
"TCPClient::transmit().send()", LastError)); | "TCPClient::transmit().send()", LastError)); | ||||
} | } | ||||
} | } | ||||
return ByteCount; // Usually: return the sent byte count. | return ByteCount; // Usually: return the sent byte count. | ||||
} | } | ||||
LastError = 0; // Clear our LastError value. | LastError = 0; // Clear our LastError value. | ||||
bool SuccessFlag = true; // Begin optimistically. | bool SuccessFlag = true; // Begin optimistically. | ||||
// Set Socket Options | // Set Socket Options | ||||
if(!OpenStage1Complete) { // If we haven't done this yet: | if(!OpenStage1Complete) { // If we haven't done this yet: | ||||
// Set SO_REUSEADDR if turned on | |||||
// Set SO_REUSEADDR if turned on | |||||
int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. | int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. | ||||
int result = // Set SO_REUSEADDR before bind(). | int result = // Set SO_REUSEADDR before bind(). | ||||
setsockopt( | setsockopt( | ||||
Network.DescriptiveError( | Network.DescriptiveError( | ||||
"TCPHost::open().setsockopt(SO_REUSEADDR)", LastError)); | "TCPHost::open().setsockopt(SO_REUSEADDR)", LastError)); | ||||
} | } | ||||
// Set SO_NOSIGPIPE if needed | |||||
// Set SO_NOSIGPIPE if needed | if( // On some systems we may have to | ||||
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
if( // On some systems we may have to | 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | ||||
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. | ||||
int TurnedOn = 1; // Prepare to turn this option on. | setsockopt( | ||||
int result = // Set SO_NOSIGPIPE. | Handle, | ||||
setsockopt( | SOL_SOCKET, | ||||
Handle, | SO_NOSIGPIPE, | ||||
SOL_SOCKET, | (char*) &TurnedOn, | ||||
SO_NOSIGPIPE, | sizeof(TurnedOn)); | ||||
(char*) &TurnedOn, | if(0 > result) { // If there was an error then | ||||
sizeof(TurnedOn)); | SuccessFlag = false; // we did not succeed. | ||||
LastError = Network.getLastError(); // Capture the error information and | |||||
if(0 > result) { // If there was an error then | throw Networking::SocketSetSockOptError( // throw. | ||||
SuccessFlag = false; // we did not succeed. | Network.DescriptiveError( | ||||
LastError = Network.getLastError(); // Capture the error information and | "TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError)); | ||||
throw Networking::SocketSetSockOptError( // throw. | } | ||||
Network.DescriptiveError( | } | ||||
"TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
} | |||||
} | |||||
OpenStage1Complete = true; // Skip this section from now on. | OpenStage1Complete = true; // Skip this section from now on. | ||||
} // Done with stage 1. | } // Done with stage 1. | ||||
//// WIN32 Strong Entropy Source == CryptGenRandom() /////////////////////////// | //// WIN32 Strong Entropy Source == CryptGenRandom() /////////////////////////// | ||||
#include <winsock2.h> | |||||
#include <windows.h> | #include <windows.h> | ||||
#include <wincrypt.h> | #include <wincrypt.h> | ||||
#include <set> | #include <set> | ||||
#include <vector> | #include <vector> | ||||
#include <string> | #include <string> | ||||
#include <queue> | #include <queue> | ||||
#include "faults.hpp" | #include "faults.hpp" | ||||
using namespace std; | using namespace std; | ||||
Pointer(P), | Pointer(P), | ||||
Type(&T), | Type(&T), | ||||
State(&S), | State(&S), | ||||
Name(N), | Name(N), | ||||
isRunning(R), | isRunning(R), | ||||
isBad(B), | isBad(B), | ||||
Fault(F) | Fault(F) | ||||
isRunning = Right.isRunning; | isRunning = Right.isRunning; | ||||
isBad = Right.isBad; | isBad = Right.isBad; | ||||
Fault = Right.Fault; | Fault = Right.Fault; | ||||
Name = Right.Name; | Name = Right.Name; | ||||
return *this; | return *this; | ||||
} | } | ||||
// When in WIN32 land... | // When in WIN32 land... | ||||
// Remember to compile (on GNU anyway) with -mthreads | // Remember to compile (on GNU anyway) with -mthreads | ||||
#include <winsock2.h> | |||||
#include <windows.h> | #include <windows.h> | ||||
#include <process.h> | #include <process.h> | ||||
// End Thread Manager | // End Thread Manager | ||||
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
//////////////////////////////////////////////////////////////////////////////// | |||||
//////////////////////////////////////////////////////////////////////////////// | // A ProductionQueue is a templated, thread safe mechanism for implementing | ||||
// A ProductionQueue is a templated, thread safe mechanism for implementing | // a producer/consumer relationship. The objects in the queue should be simple | ||||
// 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 | ||||
// data so that they can be created, destroyed, and copied without trouble. Put | // another way - the objects in the ProductionQueue should be lightweight | ||||
// another way - the objects in the ProductionQueue should be lightweight | // handles for other things. Those things should be created and destroyed | ||||
// handles for other things. Those things should be created and destroyed | // elsewhere. | ||||
// elsewhere. | template<typename T> // Templatized | ||||
class ProductionQueue { // Production Queue Class | |||||
template<typename T> // Templatized | private: | ||||
class ProductionQueue { // Production Queue Class | Mutex myMutex; // Contains a mutex and | ||||
private: | volatile unsigned int LatestSize; // a volatile (blinking light) size | ||||
Mutex myMutex; // Contains a mutex and | ProductionGateway myGateway; // integrated with a production | ||||
volatile unsigned int LatestSize; // a volatile (blinking light) size | queue<T> myQueue; // gateway and a queue. | ||||
ProductionGateway myGateway; // integrated with a production | public: | ||||
queue<T> myQueue; // gateway and a queue. | ProductionQueue() : LatestSize(0) {} // The size always starts at zero. | ||||
T take() { // To consume a queued object | |||||
public: | myGateway.consume(); // we wait on the production gateway | ||||
ProductionQueue() : LatestSize(0) {} // The size always starts at zero. | ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock | ||||
T O = myQueue.front(); // the mutext, take the object on the | |||||
T take() { // To consume a queued object | myQueue.pop(); // front of the queue, pop it out, | ||||
myGateway.consume(); // we wait on the production gateway | LatestSize = myQueue.size(); // and rest our size (blinking light). | ||||
ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock | return O; // Then return the object we got. | ||||
T O = myQueue.front(); // the mutext, take the object on the | } | ||||
myQueue.pop(); // front of the queue, pop it out, | void give(T O) { // To produce a queued object | ||||
LatestSize = myQueue.size(); // and rest our size (blinking light). | ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we | ||||
return O; // Then return the object we got. | 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. | |||||
void give(T O) { // To produce a queued object | } // When we're done it can be grabbed. | ||||
ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we | unsigned int size() { // To check the size we look at | ||||
myQueue.push(O); // get through we push our object | return LatestSize; // the blinking light. | ||||
LatestSize = myQueue.size(); // into the queue, reset our size | } | ||||
myGateway.produce(); // indicator and tell the gateway. | }; | ||||
} // When we're done it can be grabbed. | // End Production Queue | ||||
//////////////////////////////////////////////////////////////////////////////// | |||||
unsigned int size() { // To check the size we look at | |||||
return LatestSize; // the blinking light. | |||||
} | |||||
}; | |||||
// End Production Queue | |||||
//////////////////////////////////////////////////////////////////////////////// | |||||
#endif | #endif | ||||
// Platform Specific Includes ////////////////////////////////////////////////// | // Platform Specific Includes ////////////////////////////////////////////////// | ||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | ||||
#include <winsock2.h> | |||||
#include <windows.h> | #include <windows.h> | ||||
#endif | #endif | ||||
if(x < MinimumSleeperTime || | if(x < MinimumSleeperTime || | ||||
x > MaximumSleeperTime) // If it's not a good time value | x > MaximumSleeperTime) // If it's not a good time value | ||||
throw BadSleeperValue(); // then throw the exception. | throw BadSleeperValue(); // then throw the exception. | ||||
MillisecondsToSleep = x; // If it is good - set it. | MillisecondsToSleep = x; // If it is good - set it. | ||||
return MillisecondsToSleep; // Return the set value. | return MillisecondsToSleep; // Return the set value. | ||||
} | } | ||||
// a natural spiral. | // a natural spiral. | ||||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
PollTimer::PollTimer(int Nom, int Max) : | PollTimer::PollTimer(int Nom, int Max) : | ||||
NominalPollTime(MinimumSleeperTime), | NominalPollTime(MinimumSleeperTime), | ||||
MaximumPollTime(MinimumSleeperTime) { // Construction requires a | MaximumPollTime(MinimumSleeperTime) { // Construction requires a | ||||
setNominalPollTime(Nom); // nominal delay to use and | setNominalPollTime(Nom); // nominal delay to use and | ||||
setMaximumPollTime(Max); // a maximum delay to allow. | setMaximumPollTime(Max); // a maximum delay to allow. |