Browse Source

tidy namespace snfNETmgr

master
Pete McNeil 4 years ago
parent
commit
d5d8aaefca
3 changed files with 72 additions and 76 deletions
  1. 5
    5
      snfLOGmgr.hpp
  2. 40
    40
      snfNETmgr.cpp
  3. 27
    31
      snfNETmgr.hpp

+ 5
- 5
snfLOGmgr.hpp View File

void myTask(); // Write back thread task. void myTask(); // Write back thread task.


public: public:
DiscLogger(string N = "UnNamed"); // Constructs and starts the thread.
DiscLogger(std::string N = "UnNamed"); // Constructs and starts the thread.
~DiscLogger(); // Flushes and stops the thread. ~DiscLogger(); // Flushes and stops the thread.


std::string Path(const string PathName) { // Sets the file path.
std::string Path(const std::string PathName) { // Sets the file path.
cd::ScopeMutex NewSettings(BufferControlMutex); cd::ScopeMutex NewSettings(BufferControlMutex);
myPath = PathName; myPath = PathName;
return myPath; return myPath;
} }
bool OverwriteMode() { return (!inAppendMode); } // True if in overwrite mode. bool OverwriteMode() { return (!inAppendMode); } // True if in overwrite mode.


void post(const string Input, const string NewPath = ""); // Post Input to log, [set path].
void post(const std::string Input, const std::string NewPath = ""); // Post Input to log, [set path].
void flush(); // Flush right now! void flush(); // Flush right now!
bool Bad() { return (isBad); } // True if last write failed. bool Bad() { return (isBad); } // True if last write failed.
bool Good() { return (!isBad); } // True if not Bad(); bool Good() { return (!isBad); } // True if not Bad();


bool Ready; // True if we're ready to use. bool Ready; // True if we're ready to use.


void store(string& FileNameToStore); // Write the whole thing to a file.
void restore(string& FileNameToRestore); // Read the whole thing from a file.
void store(std::string& FileNameToStore); // Write the whole thing to a file.
void restore(std::string& FileNameToRestore); // Read the whole thing from a file.


time_t LastSyncTime; // time_t of last Sync event. time_t LastSyncTime; // time_t of last Sync event.
time_t LastSaveTime; // time_t of last GBUdb Save event. time_t LastSaveTime; // time_t of last GBUdb Save event.

+ 40
- 40
snfNETmgr.cpp View File

// snfNETmgr.cpp // snfNETmgr.cpp
// //
// (C) Copyright 2006 - 2009 ARM Research Labs, LLC
// (C) Copyright 2006 - 2020 ARM Research Labs, LLC
// See www.armresearch.com for the copyright terms. // See www.armresearch.com for the copyright terms.
// //
// See snfNETmgr.hpp for details. // See snfNETmgr.hpp for details.


//// snfNETmgr ///////////////////////////////////////////////////////////////// //// snfNETmgr /////////////////////////////////////////////////////////////////


const ThreadType snfNETmgr::Type("snfNETManager"); // The thread's type.
const ThreadState snfNETmgr::Sleeping("Sleeping"); // Taking a break.
const ThreadState snfNETmgr::SYNC_Connect("Connecting"); // Connecting to SYNC server.
const ThreadState snfNETmgr::SYNC_Read_Challenge("Reading challenge"); // Reading challenge.
const ThreadState snfNETmgr::SYNC_Compute_Response("Computing crypto"); // Computing crypto response.
const ThreadState snfNETmgr::SYNC_Send_Response("Sending crypto"); // Sending crypto response.
const ThreadState snfNETmgr::SYNC_Read_Availabilty("Reading Availability"); // Reading rulebase status.
const ThreadState snfNETmgr::SYNC_Send_GBUdb_Alerts("Sending GBUdb"); // Sending GBUdb alerts.
const ThreadState snfNETmgr::SYNC_Send_Status_Reports("Sending Status"); // Sending status reports.
const ThreadState snfNETmgr::SYNC_Send_Samples("Sending Samples"); // Sending message samples.
const ThreadState snfNETmgr::SYNC_Send_End_Of_Report("Sending End"); // Sending end of client data.
const ThreadState snfNETmgr::SYNC_Read_Server_Response("Reading Server"); // Reading server data.
const ThreadState snfNETmgr::SYNC_Close_Connection("Closing Connection"); // Closing connection.
const ThreadState snfNETmgr::SYNC_Parse_GBUdb_Reflections("Parsing GBUdb"); // Parsing GBUdb reflections.
const ThreadState snfNETmgr::SYNC_Log_Event("Logging SYNC"); // Logging SYNC event.
const cd::ThreadType snfNETmgr::Type("snfNETManager"); // The thread's type.
const cd::ThreadState snfNETmgr::Sleeping("Sleeping"); // Taking a break.
const cd::ThreadState snfNETmgr::SYNC_Connect("Connecting"); // Connecting to SYNC server.
const cd::ThreadState snfNETmgr::SYNC_Read_Challenge("Reading challenge"); // Reading challenge.
const cd::ThreadState snfNETmgr::SYNC_Compute_Response("Computing crypto"); // Computing crypto response.
const cd::ThreadState snfNETmgr::SYNC_Send_Response("Sending crypto"); // Sending crypto response.
const cd::ThreadState snfNETmgr::SYNC_Read_Availabilty("Reading Availability"); // Reading rulebase status.
const cd::ThreadState snfNETmgr::SYNC_Send_GBUdb_Alerts("Sending GBUdb"); // Sending GBUdb alerts.
const cd::ThreadState snfNETmgr::SYNC_Send_Status_Reports("Sending Status"); // Sending status reports.
const cd::ThreadState snfNETmgr::SYNC_Send_Samples("Sending Samples"); // Sending message samples.
const cd::ThreadState snfNETmgr::SYNC_Send_End_Of_Report("Sending End"); // Sending end of client data.
const cd::ThreadState snfNETmgr::SYNC_Read_Server_Response("Reading Server"); // Reading server data.
const cd::ThreadState snfNETmgr::SYNC_Close_Connection("Closing Connection"); // Closing connection.
const cd::ThreadState snfNETmgr::SYNC_Parse_GBUdb_Reflections("Parsing GBUdb"); // Parsing GBUdb reflections.
const cd::ThreadState snfNETmgr::SYNC_Log_Event("Logging SYNC"); // Logging SYNC event.


snfNETmgr::snfNETmgr() : // Starting up the NETmgr snfNETmgr::snfNETmgr() : // Starting up the NETmgr
Thread(snfNETmgr::Type, "NET Manager"), // Network manager and Name. Thread(snfNETmgr::Type, "NET Manager"), // Network manager and Name.
} }


void snfNETmgr::myTask() { // Here's the thread task. void snfNETmgr::myTask() { // Here's the thread task.
Sleeper WaitASecond(1000); // Heartbeat timer.
cd::Sleeper WaitASecond(1000); // Heartbeat timer.
while(false == isTimeToStop) { // Until it's time to stop, while(false == isTimeToStop) { // Until it's time to stop,
CurrentThreadState(Sleeping); // post our status, CurrentThreadState(Sleeping); // post our status,
WaitASecond(); // pause for a second, WaitASecond(); // pause for a second,
// CFGData object in order to maintain self-consistency. // CFGData object in order to maintain self-consistency.


void snfNETmgr::configure(snfCFGData& CFGData) { // Update the configuration. void snfNETmgr::configure(snfCFGData& CFGData) { // Update the configuration.
ScopeMutex CFGDataExchange(ConfigMutex); // Lock the config data during updates.
cd::ScopeMutex CFGDataExchange(ConfigMutex); // Lock the config data during updates.


// Update the internal config data from CFGData while we are locked. // Update the internal config data from CFGData while we are locked.
// Internal functions which depend on this data will lock the object, // Internal functions which depend on this data will lock the object,
case Truncate: { IPRange = "Truncate"; break; } // Don't even bother looking. case Truncate: { IPRange = "Truncate"; break; } // Don't even bother looking.
} }


SocketAddress IP;
cd::SocketAddress IP;
IP.setAddress(ScanData.SourceIPRecord().IP); IP.setAddress(ScanData.SourceIPRecord().IP);


XML << IPRange << "\' ip=\'" << (string) IP4Address(IP.getAddress()) << "\' t=\'";
XML << IPRange << "\' ip=\'" << (std::string) cd::IP4Address(IP.getAddress()) << "\' t=\'";


string IPType; string IPType;
switch(ScanData.SourceIPRecord().GBUdbData.Flag()) { switch(ScanData.SourceIPRecord().GBUdbData.Flag()) {


// Last thing we do is post the formatted string to the buffer. // Last thing we do is post the formatted string to the buffer.
const unsigned int SampleSafetyLimit = 100000; // 100 Kbyte limit on samples. const unsigned int SampleSafetyLimit = 100000; // 100 Kbyte limit on samples.
ScopeMutex DoNotDisturb(myMutex); // Don't bug me man I'm busy.
cd::ScopeMutex DoNotDisturb(myMutex); // Don't bug me man I'm busy.
if(SampleSafetyLimit < SamplesBuffer.length()) // If the samples buffer is full if(SampleSafetyLimit < SamplesBuffer.length()) // If the samples buffer is full
SamplesBuffer.clear(); // clear it before adding more. SamplesBuffer.clear(); // clear it before adding more.
SamplesBuffer.append(XML.str()); // Append the XML to the buffer. SamplesBuffer.append(XML.str()); // Append the XML to the buffer.
} }


string snfNETmgr::getSamples() { // Synchronized way to get Samples. string snfNETmgr::getSamples() { // Synchronized way to get Samples.
ScopeMutex DoNotDisturb(myMutex); // Lock the mutex to protect our work.
cd::ScopeMutex DoNotDisturb(myMutex); // Lock the mutex to protect our work.
string SamplesBatch = SamplesBuffer; // Copy the samples to a new string. string SamplesBatch = SamplesBuffer; // Copy the samples to a new string.
SamplesBuffer.clear(); // Clear the samples buffer. SamplesBuffer.clear(); // Clear the samples buffer.
return SamplesBatch; // Return a batch of Samples. return SamplesBatch; // Return a batch of Samples.


void snfNETmgr::sendReport(const string& S) { // How to send a status report. void snfNETmgr::sendReport(const string& S) { // How to send a status report.
const unsigned int ReportSafetyLimit = 100000; // 100 Kbytes limit on reports. const unsigned int ReportSafetyLimit = 100000; // 100 Kbytes limit on reports.
ScopeMutex DoNotDisturb(myMutex); // Lock the mutex for a moment.
cd::ScopeMutex DoNotDisturb(myMutex); // Lock the mutex for a moment.
if(ReportSafetyLimit < ReportsBuffer.length()) // If the reports buffer is full if(ReportSafetyLimit < ReportsBuffer.length()) // If the reports buffer is full
ReportsBuffer.clear(); // clear it before adding more. ReportsBuffer.clear(); // clear it before adding more.
ReportsBuffer.append(S); // Append the report. ReportsBuffer.append(S); // Append the report.
} }


string snfNETmgr::getReports() { // Synchronized way to get Reports. string snfNETmgr::getReports() { // Synchronized way to get Reports.
ScopeMutex DoNotDisturb(myMutex); // Lock the mutex to protect our work.
cd::ScopeMutex DoNotDisturb(myMutex); // Lock the mutex to protect our work.
string ReportsBatch = ReportsBuffer; // Copy the reports to a new string. string ReportsBatch = ReportsBuffer; // Copy the reports to a new string.
ReportsBuffer.clear(); // Clear the reports buffer. ReportsBuffer.clear(); // Clear the reports buffer.
return ReportsBatch; // Return a batch of Reports. return ReportsBatch; // Return a batch of Reports.
} }


unsigned long snfNETmgr::ResolveHostIPFromName(const string& N) { // Host name resolution tool. unsigned long snfNETmgr::ResolveHostIPFromName(const string& N) { // Host name resolution tool.
ScopeMutex OneAtATimePlease(ResolverMutex); // Resolve only one at a time.
cd::ScopeMutex OneAtATimePlease(ResolverMutex); // Resolve only one at a time.
unsigned long IP = inet_addr(N.c_str()); // See if it's an IP. unsigned long IP = inet_addr(N.c_str()); // See if it's an IP.
if (INADDR_NONE == IP) { // If it's not an IP resolve it. if (INADDR_NONE == IP) { // If it's not an IP resolve it.
hostent* H = gethostbyname(N.c_str()); // Resolve the host. hostent* H = gethostbyname(N.c_str()); // Resolve the host.
// platform solution that depends only on our own code ;-) // platform solution that depends only on our own code ;-)


void snfNETmgr::evolvePad(string Entropy) { // Add entropy and evolve. void snfNETmgr::evolvePad(string Entropy) { // Add entropy and evolve.
ScopeMutex OneAtATimePlease(PadMutex); // Protect the one time pad.
cd::ScopeMutex OneAtATimePlease(PadMutex); // Protect the one time pad.
myLOGmgr->Timestamp(Entropy); // Time matters ;-) myLOGmgr->Timestamp(Entropy); // Time matters ;-)
for(unsigned int a = 0; a < Entropy.length(); a++) { // Add the entropy to our generator. for(unsigned int a = 0; a < Entropy.length(); a++) { // Add the entropy to our generator.
PadGenerator.Encrypt(Entropy.at(a)); PadGenerator.Encrypt(Entropy.at(a));
} }
msclock rt = myLOGmgr->RunningTime(); // Get the elapsed running time so far.
cd::msclock rt = myLOGmgr->RunningTime(); // Get the elapsed running time so far.
unsigned char* rtb = reinterpret_cast<unsigned char*>(&rt); // Convert that long long into bytes. unsigned char* rtb = reinterpret_cast<unsigned char*>(&rt); // Convert that long long into bytes.
for(unsigned int a = 0; a < sizeof(msclock); a++) { // Encrypt those bytes one by one
for(unsigned int a = 0; a < sizeof(cd::msclock); a++) { // Encrypt those bytes one by one
PadGenerator.Encrypt(rtb[a]); // to add more entropy. PadGenerator.Encrypt(rtb[a]); // to add more entropy.
} }
} }
// Utility to read a line from a non-blocking TCPHost & check the timeout. // Utility to read a line from a non-blocking TCPHost & check the timeout.


const unsigned int MaxReadLineLength = 1024; // How long a line can be. const unsigned int MaxReadLineLength = 1024; // How long a line can be.
string readLineTimeout(TCPHost& S, Timeout& T) { // Read a line from S until T.
Sleeper WaitForMoreData(50); // How long to wait when no data.
string readLineTimeout(cd::TCPHost& S, cd::Timeout& T) { // Read a line from S until T.
cd::Sleeper WaitForMoreData(50); // How long to wait when no data.
string LineBuffer = ""; // Buffer for the line. string LineBuffer = ""; // Buffer for the line.
while( // Keep going as long as: while( // Keep going as long as:
false == T.isExpired() && // our timeout has not expired AND false == T.isExpired() && // our timeout has not expired AND
// delay between chunks to give the channel more time. // delay between chunks to give the channel more time.


const int MaxSendChunkSize = 512; // Size of one chunk in a write. const int MaxSendChunkSize = 512; // Size of one chunk in a write.
void sendDataTimeout(TCPHost& S, Timeout& T, char* Bfr, int Len) { // Send and keep track of time.
Sleeper WaitForMoreRoom(15); // Wait to send more data.
void sendDataTimeout(cd::TCPHost& S, cd::Timeout& T, char* Bfr, int Len) { // Send and keep track of time.
cd::Sleeper WaitForMoreRoom(15); // Wait to send more data.
int Remaining = Len; // This is how much we have left. int Remaining = Len; // This is how much we have left.
while( // For as long as: while( // For as long as:
false == T.isExpired() && // We still have time left AND false == T.isExpired() && // We still have time left AND
} // the pause before the next chunk. } // the pause before the next chunk.
} }


void sendDataTimeout(TCPHost& S, Timeout& T, string& D) { // Send a string and keep track
void sendDataTimeout(cd::TCPHost& S, cd::Timeout& T, std::string& D) { // Send a string and keep track
sendDataTimeout(S, T, const_cast<char*>(D.c_str()), D.length()); // of time. (Polymorphism is fun) sendDataTimeout(S, T, const_cast<char*>(D.c_str()), D.length()); // of time. (Polymorphism is fun)
} }




if(!isConfigured) return; // If we're not configured, don't! if(!isConfigured) return; // If we're not configured, don't!
else { else {
ScopeMutex GettingConfig(ConfigMutex); // Temporarily lock our config.
cd::ScopeMutex GettingConfig(ConfigMutex); // Temporarily lock our config.
HostName = SyncHostName; // We will connect to this host. HostName = SyncHostName; // We will connect to this host.
HostPort = SyncHostPort; // We will connect to this port. HostPort = SyncHostPort; // We will connect to this port.
Secret = SecurityKey; // Get the security key. Secret = SecurityKey; // Get the security key.
// if(SessionDog.isExpired()) throw SyncFailed("Out Of Time"); // if(SessionDog.isExpired()) throw SyncFailed("Out Of Time");


const int SyncSessionTimeout = 2 * SYNCTimer.getDuration(); // Timeout is twice poll time. const int SyncSessionTimeout = 2 * SYNCTimer.getDuration(); // Timeout is twice poll time.
Timeout SessionDog(SyncSessionTimeout); // Give this long for a session.
cd::Timeout SessionDog(SyncSessionTimeout); // Give this long for a session.


// Connect to the sync host. // Connect to the sync host.


CurrentThreadState(SYNC_Connect); CurrentThreadState(SYNC_Connect);


SocketAddress SyncHostAddress; // We'll need an address.
cd::SocketAddress SyncHostAddress; // We'll need an address.
SyncHostAddress.setPort(HostPort); // Set the port. SyncHostAddress.setPort(HostPort); // Set the port.
SyncHostAddress.setAddress(ResolveHostIPFromName(HostName)); // Resolve and set the IP. SyncHostAddress.setAddress(ResolveHostIPFromName(HostName)); // Resolve and set the IP.
TCPHost SyncServer(SyncHostAddress); // Set up a host connection.
cd::TCPHost SyncServer(SyncHostAddress); // Set up a host connection.
SyncServer.makeNonBlocking(); // Make the connection non-blocking. SyncServer.makeNonBlocking(); // Make the connection non-blocking.


PollTimer WaitForOpen(10, 340); // Expand 10ms to 340ms between tries.
cd::PollTimer WaitForOpen(10, 340); // Expand 10ms to 340ms between tries.
while(!SessionDog.isExpired()) { // Wait & Watch for a good connection. while(!SessionDog.isExpired()) { // Wait & Watch for a good connection.
try { SyncServer.open(); } // Try opening the connection. try { SyncServer.open(); } // Try opening the connection.
catch(exception& e) { // If we get an exception then catch(exception& e) { // If we get an exception then


//--- Prepare the secret. //--- Prepare the secret.


MANGLER ResponseGenerator; // Grab a mangler.
cd::MANGLER ResponseGenerator; // Grab a mangler.
for(unsigned int i = 0; i < Secret.length(); i++) // Fill it with the for(unsigned int i = 0; i < Secret.length(); i++) // Fill it with the
ResponseGenerator.Encrypt(Secret.at(i)); // security key. ResponseGenerator.Encrypt(Secret.at(i)); // security key.



+ 27
- 31
snfNETmgr.hpp View File

// snfNETmgr.hpp // snfNETmgr.hpp
// //
// (C) Copyright 2006 - 2009 ARM Research Labs, LLC.
// (C) Copyright 2006 - 2020 ARM Research Labs, LLC.
// See www.armresearch.com for the copyright terms. // See www.armresearch.com for the copyright terms.
// //
// SNF network node manager. // SNF network node manager.


// 20080312 _M Refactored exceptions to std::runtime_exception // 20080312 _M Refactored exceptions to std::runtime_exception


#ifndef snfNETmgr_included
#define snfNETmgr_included
#pragma once


#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include "snfLOGmgr.hpp" #include "snfLOGmgr.hpp"
#include "snfGBUdbmgr.hpp" #include "snfGBUdbmgr.hpp"


//namespace cd = codedweller;
namespace cd = codedweller;


class snfScanData; // Declare snfScanData; class snfScanData; // Declare snfScanData;
class snfLOGmgr; // Declare snfLOGmgr; class snfLOGmgr; // Declare snfLOGmgr;
const unsigned int SNFPadSize = 16; // Size of an SNF One Time Pad. const unsigned int SNFPadSize = 16; // Size of an SNF One Time Pad.
const unsigned int SNFSignatureSize = SNFHandshakeSize; // Size of an SNF Signature. const unsigned int SNFSignatureSize = SNFHandshakeSize; // Size of an SNF Signature.


class snfNETmgr : public Thread { // The network process manager.
class snfNETmgr : public cd::Thread { // The network process manager.
private: private:


Mutex myMutex; // Object is busy mutex.
Mutex ResolverMutex; // Mutex to protect lookups.
Mutex ConfigMutex; // Configuration change/use mutex.
Mutex PadMutex; // Pad use/evoloution mutex.
cd::Mutex myMutex; // Object is busy mutex.
cd::Mutex ResolverMutex; // Mutex to protect lookups.
cd::Mutex ConfigMutex; // Configuration change/use mutex.
cd::Mutex PadMutex; // Pad use/evoloution mutex.


snfLOGmgr* myLOGmgr; // Log manager to use. snfLOGmgr* myLOGmgr; // Log manager to use.
snfGBUdbmgr* myGBUdbmgr; // GBUdb manager to use. snfGBUdbmgr* myGBUdbmgr; // GBUdb manager to use.
volatile bool isTimeToStop; // Time to shutdown flag. volatile bool isTimeToStop; // Time to shutdown flag.
volatile bool isConfigured; // True once ready to run. volatile bool isConfigured; // True once ready to run.


Timeout SYNCTimer; // SYNC timer.
cd::Timeout SYNCTimer; // SYNC timer.


void evolvePad(string Entropy = ""); // Add entropy to and evolve.
MANGLER PadGenerator; // Random pad source.
void evolvePad(std::string Entropy = ""); // Add entropy to and evolve.
cd::MANGLER PadGenerator; // Random pad source.
PadBuffer OneTimePad(int Len = SNFPadSize); // Provides Len bytes of one time pad. PadBuffer OneTimePad(int Len = SNFPadSize); // Provides Len bytes of one time pad.


// Configuration data // Configuration data
unsigned long ResolveHostIPFromName(const string& N); // Find the IP. unsigned long ResolveHostIPFromName(const string& N); // Find the IP.
string& RulebaseUTC(string& t); // Gets local rulebase file UTC. string& RulebaseUTC(string& t); // Gets local rulebase file UTC.


const static ThreadType Type; // The thread's type.
const static ThreadState Sleeping; // Taking a break.
const static ThreadState SYNC_Connect; // Connecting to SYNC server.
const static ThreadState SYNC_Read_Challenge; // Reading challenge.
const static ThreadState SYNC_Compute_Response; // Computing crypto response.
const static ThreadState SYNC_Send_Response; // Sending crypto response.
const static ThreadState SYNC_Read_Availabilty; // Reading rulebase status.
const static ThreadState SYNC_Send_GBUdb_Alerts; // Sending GBUdb alerts.
const static ThreadState SYNC_Send_Status_Reports; // Sending status reports.
const static ThreadState SYNC_Send_Samples; // Sending message samples.
const static ThreadState SYNC_Send_End_Of_Report; // Sending end of client data.
const static ThreadState SYNC_Read_Server_Response; // Reading server data.
const static ThreadState SYNC_Close_Connection; // Closing connection.
const static ThreadState SYNC_Parse_GBUdb_Reflections; // Parsing GBUdb reflections.
const static ThreadState SYNC_Log_Event; // Logging SYNC event.
const static cd::ThreadType Type; // The thread's type.
const static cd::ThreadState Sleeping; // Taking a break.
const static cd::ThreadState SYNC_Connect; // Connecting to SYNC server.
const static cd::ThreadState SYNC_Read_Challenge; // Reading challenge.
const static cd::ThreadState SYNC_Compute_Response; // Computing crypto response.
const static cd::ThreadState SYNC_Send_Response; // Sending crypto response.
const static cd::ThreadState SYNC_Read_Availabilty; // Reading rulebase status.
const static cd::ThreadState SYNC_Send_GBUdb_Alerts; // Sending GBUdb alerts.
const static cd::ThreadState SYNC_Send_Status_Reports; // Sending status reports.
const static cd::ThreadState SYNC_Send_Samples; // Sending message samples.
const static cd::ThreadState SYNC_Send_End_Of_Report; // Sending end of client data.
const static cd::ThreadState SYNC_Read_Server_Response; // Reading server data.
const static cd::ThreadState SYNC_Close_Connection; // Closing connection.
const static cd::ThreadState SYNC_Parse_GBUdb_Reflections; // Parsing GBUdb reflections.
const static cd::ThreadState SYNC_Log_Event; // Logging SYNC event.


}; };

#endif


Loading…
Cancel
Save