From aedf3c6b46c0c278d9ea08457a4e0d400500ac8f Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Fri, 3 May 2019 11:33:00 -0500 Subject: [PATCH 01/24] Minor Update: - LogCore: Increase log buffer for larger data events --- LogCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LogCore.cpp b/LogCore.cpp index 0b1cf58..f635eeb 100644 --- a/LogCore.cpp +++ b/LogCore.cpp @@ -17,7 +17,7 @@ //--------------------------------------------------------------------------- // Global vars -char LogStr[1000]; // Temporary var to create log messages, globally available to save on memory operations +char LogStr[5000]; // Temporary var to create log messages, globally available to save on memory operations const char * LogOutputName[] = { "None", "Raw", "Normal", "Hex", "Bin" }; From cb98634b794701be5a0598b0c1bcaab6da321365 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 13 May 2019 09:33:37 +0200 Subject: [PATCH 02/24] Minor Update: - Comments added --- ApplicationCore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ApplicationCore.cpp b/ApplicationCore.cpp index 3f6a1b4..d0c4244 100644 --- a/ApplicationCore.cpp +++ b/ApplicationCore.cpp @@ -420,9 +420,9 @@ bool CApplication::Run( bool TerminateOnError ) { ProcessTerminate = !FunctionItem->Function->Process(); if (TerminateOnError) { - if (ProcessTerminate) + if (ProcessTerminate) // Raise terminate flag for other processes Terminate = true; - if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) + if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) // If needed, allow process to terminate cleanly CleanTerminate = false; } } From c723846fc94e99b689814567be2248bc7f1c3764 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 20 May 2019 17:33:35 +0200 Subject: [PATCH 03/24] Bug fix: - JSONparse: - Error deleting unused array element --- JSONparseCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index c3cce76..557e3c6 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -690,7 +690,7 @@ bool CJSONparse::ParseArray( CDataMember * Array ) SkipWhiteSpace(); if (!ParseObject( *Member ) && !Error && !ParseArray( *Member ) && !Error && !ParseString( *Member ) && !Error && !ParsePrimitive( *Member ) ) {} if (Error) { - delete Member; + delete *Member; return false; } else { From c0a50bf2bd1ca7467b55e9fbed5490d82a98f696 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 20 May 2019 18:07:25 +0200 Subject: [PATCH 04/24] Minor update: - FunctionCore: - Set Function Type in Init() - SelectableBare: - Remove unnecesary initialisation in constructor - SelectableCore: - Remove code duplicated in SelectableBare --- ApplicationCore.cpp | 6 +++--- FunctionCore.cpp | 6 ++++-- SelectableBare.cpp | 3 --- SelectableCore.cpp | 16 ---------------- 4 files changed, 7 insertions(+), 24 deletions(-) diff --git a/ApplicationCore.cpp b/ApplicationCore.cpp index 3f6a1b4..e4a5065 100644 --- a/ApplicationCore.cpp +++ b/ApplicationCore.cpp @@ -27,9 +27,9 @@ CApplication::CApplication( EDebugLevel pLogLevel ) // Set signal handlers ConfigureSignalHandlers(); - DefinitionFile = NULL; - ConfigFile = NULL; - AddressFile = NULL; + DefinitionFile = NULL; + ConfigFile = NULL; + AddressFile = NULL; // Create output logger Log = new CLogCore( stdout ); diff --git a/FunctionCore.cpp b/FunctionCore.cpp index a778ead..f902d79 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -30,9 +30,8 @@ extern CApplication * Application; CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( pType ) { // Set name - if (pName) { + if (pName) Name = strdup( pName ); - } // Logging Log = Application->Log; @@ -101,6 +100,9 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) if (!FunctionConfig ) return false; + // Set Type + FunctionConfig->SetChStr( "Type", Type ); + // Configure Logging/Debugging LogConfig = FunctionConfig->GetChild( "Log", true ); pLogLevel = Log->ReadLogLevel( LogConfig ); diff --git a/SelectableBare.cpp b/SelectableBare.cpp index f9aa630..b0603c9 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -38,9 +38,6 @@ CSelectableBare::CSelectableBare( const char * pName, const char * pType ) : CFu { // Quick access Selector = Application->Selector; - - // Handles - FirstHandle = NULL; } //--------------------------------------------------------------------------- diff --git a/SelectableCore.cpp b/SelectableCore.cpp index a54d54c..99575b4 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -42,27 +42,11 @@ CFunctionCore * NewSelectableCore( const char * Name ) { CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CSelectableBare( pName, pType ) { - // Quick access - Selector = Application->Selector; } //--------------------------------------------------------------------------- CSelectableCore::~CSelectableCore() { - THandle * NextHandle = NULL; - - // Destroy File Handles - while (FirstHandle) - { - // Close handle if open - if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) { - Close( FirstHandle, false ); - } - - NextHandle = FirstHandle->Next; - DestroyHandle( FirstHandle ); - FirstHandle = NextHandle; - } } //--------------------------------------------------------------------------- From 316b27b19f833775f26fc9101b0ead56d57c6ad9 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Wed, 22 May 2019 15:35:27 +0200 Subject: [PATCH 05/24] Important Update: - DeviceCore: - Allow adjustable reply timeout with SetWaitForReply() --- DeviceCore.cpp | 4 +++- DeviceCore.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 056ec7a..961a72d 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -432,6 +432,7 @@ bool CDeviceCore::SetPollParam( int pPollInterval ) bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries ) { + DefReplyTimeout = pReplyTimeout; ReplyTimeout = pReplyTimeout; MaxRetries = pMaxRetries; return true; @@ -456,12 +457,13 @@ bool CDeviceCore::DeviceOnline( TDevice * Device, bool Online ) } //--------------------------------------------------------------------------- -void CDeviceCore::SetWaitForReply() +void CDeviceCore::SetWaitForReply( int CustomTimeout ) { // Start timer SetStartTime( &PollWait ); // Set flag + ReplyTimeout = (CustomTimeout >= 0)? CustomTimeout : DefReplyTimeout; WaitingForReply = true; InvalidReply = false; } diff --git a/DeviceCore.h b/DeviceCore.h index 427243a..71b3ffb 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -145,6 +145,7 @@ protected: // Reply bool WaitingForReply; // Command sent, waiting for reply bool InvalidReply; // Invalid reply received + long DefReplyTimeout; // Default Max waiting time for reply long ReplyTimeout; // Max waiting time for reply // Retry @@ -306,7 +307,7 @@ protected: virtual bool DeviceOnline( TDevice * Device, bool Online ); // Handle Reply Timing - virtual void SetWaitForReply(); + virtual void SetWaitForReply( int CustomTimeout = -1 ); virtual void ValidReplyReceived(); virtual bool CheckReplyTimeout(); From ac649bf4fbfe93ee957ccc0362f4ca6c2bd3c2fe Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Tue, 28 May 2019 09:22:28 +0200 Subject: [PATCH 06/24] Minor Update: - DeviceCore: - Initialise params in header file - JSONparseCore: - Increase Read buffer to handle large queries - UtilCore: - Bug fix: handle NULL seperator in Hex conversions --- DeviceCore.cpp | 13 +------------ DeviceCore.h | 34 +++++++++++++++++----------------- JSONparseCore.cpp | 2 +- UtilCore.cpp | 4 ++-- 4 files changed, 21 insertions(+), 32 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 961a72d..167b93c 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -18,7 +18,7 @@ // Global Vars extern char * ProcessName; -extern CApplication * Application; +//extern CApplication * Application; //--------------------------------------------------------------------------- @@ -30,20 +30,9 @@ extern CApplication * Application; CDeviceCore::CDeviceCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType ) { // Polling - PollCycle = 0; - PollStep = 0; - PollInterval = 250; SetStartTime( &PollWait ); - WaitingForReply = false; - ReplyTimeout = 200; - InvalidReply = false; - - PollRetry = 0; - MaxRetries = 3; - // Data Structures - DeviceInit = true; ConfigTypes = new CDataMember(); ValueTree = new CDataMember(); JSONparse = new CJSONparse(); diff --git a/DeviceCore.h b/DeviceCore.h index 71b3ffb..7d601d5 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -121,10 +121,10 @@ class CDeviceCore : public CFunctionCore { protected: // Configuration - CDataMember * ConfigTypes = NULL; - CDataMember * ValueTree = NULL; - CJSONparse * JSONparse = NULL; - bool DeviceInit = false; + CDataMember * ConfigTypes = NULL; + CDataMember * ValueTree = NULL; + CJSONparse * JSONparse = NULL; + bool DeviceInit = false; // Initialise device on start // Devices & Type TDevice * FirstDeviceType = NULL; @@ -132,25 +132,25 @@ protected: TDevice * ActiveDevice = NULL; // Standard channels - TChannel * DeviceChannel = NULL; - TChannel * CmdChannel = NULL; - TChannel * EventChannel = NULL; + TChannel * DeviceChannel = NULL; + TChannel * CmdChannel = NULL; + TChannel * EventChannel = NULL; // Poll - int PollCycle; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown - int PollStep; // Position in polling sequence - timeval PollWait; // Time at which last poll was done - long PollInterval; // Minimum delay between polls + int PollCycle = 0; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown + int PollStep = 0; // Position in polling sequence + timeval PollWait = {0,0}; // Time at which last poll was done + long PollInterval = 250; // Minimum delay between polls // Reply - bool WaitingForReply; // Command sent, waiting for reply - bool InvalidReply; // Invalid reply received - long DefReplyTimeout; // Default Max waiting time for reply - long ReplyTimeout; // Max waiting time for reply + bool WaitingForReply = false; // Command sent, waiting for reply + bool InvalidReply = false; // Invalid reply received + long DefReplyTimeout = 500; // Default Max waiting time for reply + long ReplyTimeout = 500; // Max waiting time for reply // Retry - int PollRetry; // No of polling retries that has timed out - int MaxRetries; // Max allowed retries + int PollRetry = 0; // No of polling retries that has timed out + int MaxRetries = 3; // Max allowed retries // Manage Devices bool DestroyDevice( TDevice ** Device ); diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index 557e3c6..1cb53a1 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -272,7 +272,7 @@ bool CJSONparse::ReadFromHandle( const char * BasePath, int Handle, bool pRefill InputHandle = Handle; // Load Buffer - CreateBuffer( 500 ); + CreateBuffer( 1000 ); if (!FillBuffer()) { Error = true; sprintf( ErrorText, "Could not read from file" ); diff --git a/UtilCore.cpp b/UtilCore.cpp index 660897c..0f079d1 100644 --- a/UtilCore.cpp +++ b/UtilCore.cpp @@ -75,7 +75,7 @@ char * BytesToHexStr( const char * Bytes, const int Len, const char * Separator, // Print Hex values of individual bytes for (int i=0; i Date: Sun, 2 Jun 2019 16:12:42 +0200 Subject: [PATCH 07/24] Important Update: - Remove unused: FunctionCore-ChannelBuffer - DataTreeCore: - Bug fix: Set Len=0 on element Clear() - SelectableBare/Core: - Move move BuildArgs() to SelectableBare - Make OutputHandle() to virtual method - UtilCore: - Bug fix: Handle NoCrLF correctly in BytesToSafeStr() --- DataTreeCore.cpp | 8 +- FunctionCore-ChannelBuffer.h | 222 ----------------------------------- SelectableBare.cpp | 79 ------------- SelectableCore.cpp | 78 +++++++++++- SelectableCore.h | 11 +- UtilCore.cpp | 5 +- 6 files changed, 91 insertions(+), 312 deletions(-) delete mode 100644 FunctionCore-ChannelBuffer.h diff --git a/DataTreeCore.cpp b/DataTreeCore.cpp index 8f4c7e5..6f6b05f 100644 --- a/DataTreeCore.cpp +++ b/DataTreeCore.cpp @@ -131,10 +131,8 @@ CDataMember * CDataMember::CreateChild( const char * Name, const int Len ) bool CDataMember::Clear() { // Clear value - if (Value) { + if (Value) free( Value ); - Value = NULL; - } // Clear children while (FirstChild) { @@ -142,7 +140,9 @@ bool CDataMember::Clear() } // Reset value - Type = jtNull; + Type = jtNull; + Value = NULL; + Len = 0; return true; } //--------------------------------------------------------------------------- diff --git a/FunctionCore-ChannelBuffer.h b/FunctionCore-ChannelBuffer.h deleted file mode 100644 index 7af897d..0000000 --- a/FunctionCore-ChannelBuffer.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * FunctionCore.h - * - * Created on: 18 May 2016 - * Author: wentzelc - */ - -#ifndef REDACORE_FUNCTIONCORE_H_ -#define REDACORE_FUNCTIONCORE_H_ - -// Standard C/C++ Libraries -/* none */ - -// redA Libraries -#include "LogCore.h" -#include "DataTreeCore.h" -#include "CharBufferCore.h" -#include "ItemBufferCore.h" - -//--------------------------------------------------------------------------- - -// Preview -typedef struct SChannel TChannel; -typedef struct SChannelLink TChannelLink; -typedef struct SProcessBuffer TProcessBuffer; -typedef struct SProcessItem TProcessItem; - -class CFunctionCore; - -//--------------------------------------------------------------------------- - -struct SChannel -{ - char * Name; - - TChannelLink * FirstInput; - TChannelLink * FirstOutput; - - bool InputEnabled; - bool OutputEnabled; - - TProcessBuffer * InputBuffer; - - TChannel * Next; -}; -//--------------------------------------------------------------------------- - -struct SChannelLink -{ - CFunctionCore * Function; - char * Name; - - SChannelLink * Next; -}; -//--------------------------------------------------------------------------- - -struct SProcessBuffer -{ - // Process buffer - char * Name; // Name of buffer; - CItemBufferCore Buffer; // Message buffer - unsigned long LastRefNo; // Last RefNo for item - - // Input parameters - bool PassthroughCallback; // Send Callback once processed message has been passed on, else once processed - - // Output parameters - TChannel * OutputChannel; // Channel to which to pass buffer output - bool OutputCallback; // Expect callback on output? - - TProcessBuffer * Next; // Next buffer in list -}; -//--------------------------------------------------------------------------- - -struct SProcessItem -{ - // Input Parameters - TChannel * SourceChannel; - char * SourceRef; - bool SourceCallback; - - // Processing Parameters - bool Processed; - bool Completed; - - // Output Parameters - timeval CallbackTimer; - TChannelLink FirstOutput; - - // Input Data - void * DataIn; - int DataInLen; - - // Output Data - void * DataOut; - int DateOutLen; -}; -//--------------------------------------------------------------------------- - -class CFunctionCore_not_used -{ -protected: - // Function Definition - char * Name; - char * Type; - - // Configuration - CDataTree * DataTree; - TDataMember * ConfigMember; - TDataMember * LinkConfigMember; - - // Channels - TChannel * FirstChannel; - - // Processing Queues - TProcessBuffer * FirstProcessBuffer; - - // Logging - CLogCore * Log; - EDebugLevel LogLevel; - int LogOutput; - - // Stored Output - char * StoredOutput; - int StoredOutputLen; - - // Manage Channel - inline TChannel * GetChannel( const char * Name ) { - if (!Name) return NULL; - TChannel * Channel = FirstChannel; - while (Channel && strcmp( Name, Channel->Name )) - Channel = Channel->Next; - return Channel; - } - - // Load configuration - virtual bool LoadConfigData(); - virtual bool LoadChannelLinkData(); - - // Data Input/Output - virtual int Output( const TChannel * Channel, const char * Data, int Len ); - virtual bool PullInput( TChannel * Channel ); - - // Processing Queue - TProcessItem * CreateProcessItem(); - -public: - // Life cycle - CFunctionCore_not_used( const char * pName, const char * Type ); - virtual ~CFunctionCore_not_used(); - - // Load Configuration - virtual bool Init(); - - bool InitConfig( const char * pConfigPath ); - bool InitConfig( TDataMember * pConfigMember ); - - bool InitChannelLinks( const char * pLinkConfigPath ); - bool InitChannelLinks( TDataMember *pLinkConfigMember ); - - // Set Parameters Manually - bool SetLogParam( EDebugLevel pDebugLevel, int pOutputDisplay ); - bool SetLogLevel( EDebugLevel pDebugLevel ); - - // Miscellaneous - inline const char * GetName() { return Name; }; - inline const char * GetType() { return Type; }; - - // Manage Channels - virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true ); - inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) { - TChannel * Channel = GetChannel( ChannelName ); - if (!Channel) return false; - Channel->OutputEnabled = pOutputEnable; - return true; - } - inline bool SetChannelInEnable( const char * ChannelName, const bool pInputEnable ) { - TChannel * Channel = GetChannel( ChannelName ); - if (!Channel) return false; - Channel->InputEnabled = pInputEnable; - return true; - } - inline bool isInputEnabled( const char * ChannelName ) { - TChannel * Channel = GetChannel( ChannelName ); - return ((Channel)? Channel->InputEnabled : false); - } - inline bool isOutputEnabled( const char * ChannelName ) { - TChannel * Channel = GetChannel( ChannelName ); - return ((Channel)? Channel->OutputEnabled : false); - } - - // Pushing Data Output -> Input - virtual int Output( const char * ChannelName, const char * Data, int Len = -1 ); - virtual int Input( const char * ChannelName, const char * Data, int Len = -1 ); - - // Pulling Data Input <- Output - virtual bool PullInput( const char * ChannelName ); - virtual bool PullOutput( const char * ChannelName, char ** Data, int * Len = NULL ); - - // Manages Process Buffers - TProcessBuffer * CreateProcessBuffer( const char * Name ); - TProcessBuffer * GetProcessBuffer( const char * Name ); - - TProcessItem * CreateProcessItem( const char * BufferName ); - TProcessItem * GetProcessItem( const char BufferName, const int Ref ); - bool DestroyProcessItem( const char * BufferName, const int Ref ); - - // Queued Output - virtual bool OutputMessage( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo, bool Callback, const char * Data, int Len = -1 ); - virtual bool OutputMessageCallback( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo, const bool Success, const char * Error ); - virtual bool InputMessage( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo, bool Callback, const char * Data, int Len = -1 ); - virtual bool InputMessageCancel( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo ); - - // Automated Data Input/Output - virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional ); - virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ); - virtual bool Process() = 0; -}; - -//--------------------------------------------------------------------------- - -#endif /* REDACORE_FUNCTIONCORE_H_ */ diff --git a/SelectableBare.cpp b/SelectableBare.cpp index b0603c9..04be540 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -873,82 +873,3 @@ bool CSelectableBare::Process() return true; } //--------------------------------------------------------------------------- - -bool CSelectableBare::BuildArgs( const char * ExecPath, int &Count, char * Args[] ) -{ - bool ParamStarted = false; - bool OpenQuotes = false; - char * MatchPos = NULL; - char * StartPos = NULL; - int Len; - - // Validate - if (!ExecPath || !*ExecPath) { - return false; - } - - // Split params - MatchPos = (char*)ExecPath; - for (;;) - { - // Look for whitespace - if (!ParamStarted) - { - // Quotes starts quoted parameter - if (*MatchPos == '"') { - ParamStarted = true; - OpenQuotes = true; - StartPos = MatchPos+1; // Skip starting quote - } - // Non-whitespace starts normal parameter - else if ((*MatchPos != ' ') && (*MatchPos != 0)) { - ParamStarted = true; - StartPos = MatchPos; - } - } - else if (OpenQuotes) - { - // Another quote ends parameter - if (*MatchPos == '"') { - Len = MatchPos-StartPos-1; // Skip end quote - Args[Count] = (char*)malloc( Len+1 ); - strncpy( Args[Count], StartPos, Len ); - Args[Count][Len] = 0; - Count++; - ParamStarted = false; - OpenQuotes = false; - } - } - else - { - // Whitespace ends parameter - if ((*MatchPos == ' ') || (*MatchPos == 0)) { - Len = MatchPos-StartPos; - Args[Count] = (char*)malloc( Len+1 ); - strncpy( Args[Count], StartPos, Len ); - Args[Count][Len] = 0; - Count++; - ParamStarted = false; - } - } - // Next char, unless NULL - if (*MatchPos) - MatchPos++; - else - break; - } - - // Check all parameters closed - if (ParamStarted) { - Count = 0; - Args[0] = NULL; - return false; - } - - // Set last Param to NULL - Args[Count] = NULL; - - return true; -} -//--------------------------------------------------------------------------- - diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 99575b4..1f9537b 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -1254,7 +1254,6 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) strcpy( ClientAddress, inet_ntoa(address.sin_addr) ); sprintf( ClientPort, "%d", ntohs(address.sin_port) ); - // Get end of client list RemoteClient = &FirstHandle; while (*RemoteClient) { @@ -2455,3 +2454,80 @@ bool CSelectableCore::ReadSerialConfig( THandle * Handle ) } //--------------------------------------------------------------------------- +bool CSelectableCore::BuildArgs( const char * ExecPath, int &Count, char * Args[] ) +{ + bool ParamStarted = false; + bool OpenQuotes = false; + char * MatchPos = NULL; + char * StartPos = NULL; + int Len; + + // Validate + if (!ExecPath || !*ExecPath) { + return false; + } + + // Split params + MatchPos = (char*)ExecPath; + for (;;) + { + // Look for whitespace + if (!ParamStarted) + { + // Quotes starts quoted parameter + if (*MatchPos == '"') { + ParamStarted = true; + OpenQuotes = true; + StartPos = MatchPos+1; // Skip starting quote + } + // Non-whitespace starts normal parameter + else if ((*MatchPos != ' ') && (*MatchPos != 0)) { + ParamStarted = true; + StartPos = MatchPos; + } + } + else if (OpenQuotes) + { + // Another quote ends parameter + if (*MatchPos == '"') { + Len = MatchPos-StartPos-1; // Skip end quote + Args[Count] = (char*)malloc( Len+1 ); + strncpy( Args[Count], StartPos, Len ); + Args[Count][Len] = 0; + Count++; + ParamStarted = false; + OpenQuotes = false; + } + } + else + { + // Whitespace ends parameter + if ((*MatchPos == ' ') || (*MatchPos == 0)) { + Len = MatchPos-StartPos; + Args[Count] = (char*)malloc( Len+1 ); + strncpy( Args[Count], StartPos, Len ); + Args[Count][Len] = 0; + Count++; + ParamStarted = false; + } + } + // Next char, unless NULL + if (*MatchPos) + MatchPos++; + else + break; + } + + // Check all parameters closed + if (ParamStarted) { + Count = 0; + Args[0] = NULL; + return false; + } + + // Set last Param to NULL + Args[Count] = NULL; + + return true; +} +//--------------------------------------------------------------------------- diff --git a/SelectableCore.h b/SelectableCore.h index 16df503..087caf7 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -217,9 +217,6 @@ protected: // Buffer operations virtual bool ProcessInputBuffer( THandle * Handle, bool Force ); - // Specific operations - bool BuildArgs( const char * ExecPath, int &Count, char * Args[] ); - // Convert string to lower case inline char * strlcase( char * Str ) { for (char * Ch = Str; *Ch; Ch++ ) @@ -295,7 +292,7 @@ public: // Function Interface virtual int Input( const char * ChannelName, const char * Buffer, int BufLen = -1 ); - int OutputHandle( THandle * Handle, const char * Data, int Len ); + virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual bool Process(); }; @@ -319,6 +316,7 @@ protected: // Socket Operations bool ResolveAddress( THandle * Handle, bool DelayResolve ); + THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve ); THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort ); THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve ); @@ -330,6 +328,9 @@ protected: int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen ); int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force ); + // Specific operations + bool BuildArgs( const char * ExecPath, int &Count, char * Args[] ); + public: // Life Cycle CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE ); @@ -353,7 +354,7 @@ public: virtual bool Write( THandle * Handle ); // Function Interface - int OutputHandle( THandle * Handle, const char * Data, int Len ); + virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual bool Process(); }; diff --git a/UtilCore.cpp b/UtilCore.cpp index 0f079d1..cbbfd11 100644 --- a/UtilCore.cpp +++ b/UtilCore.cpp @@ -40,7 +40,10 @@ char * BytesToSafeStr( const char * Bytes, const int Len, const bool NoCrLf, con // Remove special char for (int i=0; i 126)) || + if ((Bytes[i] == '\r') || (Bytes[i] == '\n')) { + *BufPos = (NoCrLf)? SpecChar : Bytes[i]; + } + else if (((Bytes[i] < 32) || (Bytes[i] > 126)) || (NoCrLf && ((Bytes[i] == '\r') || (Bytes[i] == '\n')))) { *BufPos = SpecChar; } From fa6825b72ad606f8a9a90ee46892bd602bccb42e Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Tue, 4 Jun 2019 18:35:23 +0200 Subject: [PATCH 08/24] Important Update: - FunctionCore/SelectableCore/FileCore/DeviceCore: - Remove InputChannels - Only OutputChannels -> LinkedChannels - Remove PullInput/Output() methods - Remove StoredOutput - Add References to channels and linked channels - Send SourceRef with output - Receive TargetRef with input - Filter output channels based on TargetRef --- DeviceCore.cpp | 16 +-- FileCore.cpp | 2 +- FileCore.h | 2 +- FunctionCore.cpp | 239 ++++++++++----------------------------------- FunctionCore.h | 29 +++--- SelectableBare.cpp | 26 ++--- SelectableCore.h | 2 +- 7 files changed, 84 insertions(+), 232 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 167b93c..42d86c3 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -1575,7 +1575,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons } else { strcat( OutputStr, "\n" ); - Output( ChannelName, OutputStr, strlen(OutputStr) ); + Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } @@ -1584,7 +1584,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Get", ProcessName, Name, ChannelName, OutputStr ); strcat( OutputStr, "\n" ); - Output( ChannelName, OutputStr, strlen(OutputStr) ); + Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } else if (!strcasecmp( "set", Value )) @@ -1621,7 +1621,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons } else { sprintf( OutputStr, "> set %s,%s = %s\n", Device->Name, Param->Name, Value ); - Output( ChannelName, OutputStr ); + Output( ChannelName, NULL, true, OutputStr ); } } @@ -1630,7 +1630,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Set", ProcessName, Name, ChannelName, OutputStr ); strcat( OutputStr, "\n" ); - Output( ChannelName, OutputStr, strlen(OutputStr) ); + Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } else if (!strcasecmp( "status", Value )) @@ -1650,7 +1650,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons } else { sprintf( OutputStr, "> %s - %s\n", Device->Name, ((Device->Online)? "online" : "offline") ); - Output( ChannelName, OutputStr ); + Output( ChannelName, NULL, true, OutputStr ); } // Report error @@ -1658,7 +1658,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Status", ProcessName, Name, ChannelName, OutputStr ); strcat( OutputStr, "\n" ); - Output( ChannelName, OutputStr, strlen(OutputStr) ); + Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } else @@ -1668,7 +1668,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s', %s%s", ProcessName, Name, ChannelName, Value, OutputStr ); strcat( OutputStr, " (comma separated values)\n" ); - Output( ChannelName, OutputStr, strlen(OutputStr) ); + Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } return MaxLen; } @@ -1719,7 +1719,7 @@ bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) default : break; } - Output( Param->EventChannel, Message, strlen(Message) ); + Output( Param->EventChannel, NULL, true, Message, strlen(Message) ); // Reset timer if (Param->EventInterval) { diff --git a/FileCore.cpp b/FileCore.cpp index 6a96902..b0a3ac1 100644 --- a/FileCore.cpp +++ b/FileCore.cpp @@ -260,7 +260,7 @@ int CFileCore::WriteToFD( int FD, const char * Data, int Len ) //--------------------------------------------------------------------------- // Manual Data Input/Output -int CFileCore::Input( const char * ChannelName, const char * Data, int Len ) +int CFileCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len ) { TFileHandle * FileHandle = NULL; int BytesWritten = 0; diff --git a/FileCore.h b/FileCore.h index e414270..3c2d957 100644 --- a/FileCore.h +++ b/FileCore.h @@ -73,7 +73,7 @@ public: virtual bool SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout ); // Data Input - virtual int Input( const char * ChannelName, const char * Data, int Len = -1 ); + virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 ); // Processing data virtual bool Process(); diff --git a/FunctionCore.cpp b/FunctionCore.cpp index f902d79..1fdda9a 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -51,26 +51,18 @@ CFunctionCore::~CFunctionCore() // Destroy Parameters if (FirstChannel->Name) { free( FirstChannel->Name ); - } - - // Destroy Linked Inputs - while (FirstChannel->FirstInput) { - if (FirstChannel->FirstInput->Name) { - free( FirstChannel->FirstInput->Name ); - } - NextLinkedChannel = FirstChannel->FirstInput->Next; - delete FirstChannel->FirstInput; - FirstChannel->FirstInput = NextLinkedChannel; + free( FirstChannel->Ref ); } // Destroy Linked Outputs - while (FirstChannel->FirstOutput) { - if (FirstChannel->FirstOutput->Name) { - free( FirstChannel->FirstOutput->Name ); + while (FirstChannel->FirstLink) { + if (FirstChannel->FirstLink->Name) { + free( FirstChannel->FirstLink->Name ); + free( FirstChannel->FirstLink->Ref ); } - NextLinkedChannel = FirstChannel->FirstOutput->Next; - delete FirstChannel->FirstOutput; - FirstChannel->FirstOutput = NextLinkedChannel; + NextLinkedChannel = FirstChannel->FirstLink->Next; + delete FirstChannel->FirstLink; + FirstChannel->FirstLink = NextLinkedChannel; } // Destroy Channel @@ -152,7 +144,7 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig ) while (FunctionMember) { // Get Parameters - LinkOutputChannel( Channel->Name, + LinkChannel( Channel->Name, FunctionMember->GetChStr( "Function" ), FunctionMember->GetChStr( "Channel" ), FunctionMember->GetChBool( "Bidirectional" ) ); @@ -205,6 +197,7 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu // Set Name (*Channel)->Name = strdup( ChannelName ); + sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName ); // Log Event if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created", @@ -220,48 +213,7 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu //--------------------------------------------------------------------------- // Automated Data Input/Output -bool CFunctionCore::LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional ) -{ - CFunctionCore * OutFunction = NULL; - TChannel * Channel = NULL; - TChannelLink ** LinkedChannel = NULL; - - // Get Channel - if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) { - return false; - } - - // Check if linked Channel exists - LinkedChannel = &(Channel->FirstInput); - while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) { - LinkedChannel = &((*LinkedChannel)->Next); - } - - // Create if not found - if (!*LinkedChannel) - { - // Create - *LinkedChannel = new TChannelLink; - - // Set Parameters - (*LinkedChannel)->Function = OutFunction; - (*LinkedChannel)->Name = strdup( OutChannelName ); - - // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Input Linked - '%s'/'%s' <-- '%s'/'%s'", - ProcessName, Name, Name, ChannelName, OutFunction->GetName(), OutChannelName ); - } - - // Link Return direction as well - if (Bidirectional) { - return OutFunction->LinkInputChannel( OutChannelName, Name, ChannelName, false ); - } - - return true; -} -//--------------------------------------------------------------------------- - -bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ) +bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Bidirectional ) { TChannel * OutChannel = NULL; CFunctionCore * InFunction = NULL; @@ -270,14 +222,14 @@ bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * In // Check if Channels & Function exist if (!(OutChannel = GetChannel( ChannelName )) || - !(InFunction = Application->GetFunction( InFunctionName )) || - !(InChannel = InFunction->GetChannel( InChannelName )) ) { + !(InFunction = Application->GetFunction( LinkFunctionName )) || + !(InChannel = InFunction->GetChannel( LinkChannelName )) ) { return false; } // Check if linked Channel exists - LinkedChannel = &(OutChannel->FirstOutput); - while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) { + LinkedChannel = &(OutChannel->FirstLink); + while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, LinkChannelName ) )) { LinkedChannel = &((*LinkedChannel)->Next); } @@ -289,80 +241,80 @@ bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * In // Set Parameters (*LinkedChannel)->Function = InFunction; - (*LinkedChannel)->Name = strdup( InChannelName ); + (*LinkedChannel)->Name = strdup( LinkChannelName ); + sprintf( (*LinkedChannel)->Ref, "%s/%s", LinkFunctionName, LinkChannelName ); // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s'/'%s' --> '%s'/'%s'", - ProcessName, Name, Name, ChannelName, InFunction->GetName(), InChannelName ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s/%s' --> '%s/%s'", + ProcessName, Name, Name, ChannelName, LinkFunctionName, LinkChannelName ); } // Link return direction as well if (Bidirectional) { - return InFunction->LinkOutputChannel( InChannelName, Name, ChannelName, false ); + return InFunction->LinkChannel( LinkChannelName, Name, ChannelName, false ); } return true; } //--------------------------------------------------------------------------- -// Manual Data Input/Output -int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len ) +int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len ) { - TChannel * Channel = NULL; + TChannel * Channel = NULL; // Validate - if (!ChannelName || !Data) { + if (!ChannelName || !*ChannelName || !Data) { return 0; } // Get Channel if (!(Channel = GetChannel( ChannelName ))) { // Channel not found - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } else if (!Channel->InputEnabled) { // Channel disabled - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'-'%s' - Input rejected, Channel input disabled", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else { - // Return processed bytes - if (Len == -1) { - Len = strlen( Data ); - } - if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:", - ProcessName, Name, ChannelName ); - return Len; + + // Return processed bytes + if (Len == -1) { + Len = strlen( Data ); } + if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); + return Len; + } //--------------------------------------------------------------------------- -int CFunctionCore::Output( const char * ChannelName, const char * Data, int Len ) +int CFunctionCore::Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len ) { TChannel * Channel = NULL; // Validate - if (!ChannelName) { + if (!ChannelName || !*ChannelName) { return 0; } // Get Channel if (!(Channel = GetChannel( ChannelName ))) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel not found", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Output rejected, Output Channel not found", + ProcessName, Name, ChannelName, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); return 0; } else { // Return processed bytes - return Output( Channel, Data, Len ); + return Output( Channel, TargetRef, SourceRef, Data, Len ); } } //--------------------------------------------------------------------------- -int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat ) +int CFunctionCore::Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat ) { TChannelLink * OutChannel = NULL; int TempLen = 0; @@ -376,22 +328,23 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len, // Check if enabled if (!Channel->OutputEnabled) { if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel output disabled", - ProcessName, Name, Channel->Name ); + ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); return 0; } // Log event if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:", - ProcessName, Name, Channel->Name ); + ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); // Pass output to all linked inputs - if (Len == -1) { + if (Len == -1) Len = strlen( Data ); - } - OutChannel = Channel->FirstOutput; + OutChannel = Channel->FirstLink; while (OutChannel) { - TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len ); - OutLen = (TempLen > OutLen)? TempLen : OutLen; + if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, OutChannel->Ref )) { + TempLen = OutChannel->Function->Input( OutChannel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len ); + OutLen = (TempLen > OutLen)? TempLen : OutLen; + } OutChannel = OutChannel->Next; } @@ -399,97 +352,3 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len, return OutLen; } //--------------------------------------------------------------------------- - -bool CFunctionCore::PullInput( const char * ChannelName ) -{ - TChannel * Channel = NULL; - - // Validate - if (!ChannelName) { - return false; - } - - // Get Channel - if (!(Channel = GetChannel( ChannelName ))) { - // Channel not found - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input failed, Channel not found", - ProcessName, Name, ChannelName ); - return false; - } - else { - // Return success - return PullInput( Channel ); - } -} -//--------------------------------------------------------------------------- - -bool CFunctionCore::PullInput( TChannel * Channel ) -{ - TChannelLink * InChannel = NULL; - char ** Data = NULL; - int * Len = NULL; - - // Validate - if (!Channel) { - return false; - } - - // Check if enabled - if (!Channel->InputEnabled) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input failed, Channel input disabled", - ProcessName, Name, Channel->Name ); - return false; - } - - // Pass output to all linked inputs - InChannel = Channel->FirstInput; - while (InChannel) - { - // Pull Output from Channel - if (InChannel->Function->PullOutput( InChannel->Name, Data, Len )) - { - // Use input - Input( Channel->Name, *Data, ((*Len)? *Len : -1) ); - } - InChannel = InChannel->Next; - } - - // Return success - return Len; -} -//--------------------------------------------------------------------------- - -bool CFunctionCore::PullOutput( const char * ChannelName, char ** Data, int * Len ) -{ - TChannel * Channel = NULL; - int TempLen = 0; - - // Validate - if (!ChannelName || !Data) { - return 0; - } - - // Get Channel - if (!(Channel = GetChannel( ChannelName ))) { - // Channel not found - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output failed, Channel not found", - ProcessName, Name, ChannelName ); - return 0; - } - else if (!Channel->InputEnabled) { - // Channel disabled - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output failed, Channel output disabled", - ProcessName, Name, ChannelName ); - return 0; - } - else { - // Return processed bytes - *Data = StoredOutput; - TempLen = (*Data)? strlen(*Data) : 0; - if (Len) *Len = TempLen; - if (Log) Log->Output( LogLevel, dlHigh, LogOutput, ((*Data)? *Data : "(NULL)"), TempLen, "%s/%s: Channel '%s' - IN:", - ProcessName, Name, ChannelName ); - return Len; - } -} -//--------------------------------------------------------------------------- diff --git a/FunctionCore.h b/FunctionCore.h index 11177af..a82c1f9 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -28,12 +28,14 @@ class CFunctionCore; struct SChannel { char * Name = NULL; + char * Ref = NULL; - TChannelLink * FirstInput = NULL; - TChannelLink * FirstOutput = NULL; + TChannelLink * FirstLink = NULL; // List of channels from which input can be received - bool InputEnabled = NULL; - bool OutputEnabled = NULL; + bool InputEnabled = NULL; // Can Channel receive input + bool OutputEnabled = NULL; // Can channel receive output + + bool Ready = false; // Channel ready to receive input TChannel * Next = NULL; }; @@ -43,6 +45,7 @@ struct SChannelLink { CFunctionCore * Function = NULL; char * Name = NULL; + char * Ref = NULL; SChannelLink * Next = NULL; }; @@ -73,10 +76,6 @@ protected: EDebugLevel LogLevel = dlNone; int LogOutput = loNone; - // Stored Output - char * StoredOutput = NULL; - int StoredOutputLen = 0; - // Manage Channel inline TChannel * GetChannel( const char * pName ) { if (!pName) return NULL; @@ -87,8 +86,7 @@ protected: } // Data Input/Output - virtual int Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat = loNone ); - virtual bool PullInput( TChannel * Channel ); + virtual int Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat = loNone ); public: // Life cycle @@ -131,16 +129,11 @@ public: } // Pushing Data Output -> Input - virtual int Output( const char * ChannelName, const char * Data, int Len = -1 ); - virtual int Input( const char * ChannelName, const char * Data, int Len = -1 ); - - // Pulling Data Input <- Output - virtual bool PullInput( const char * ChannelName ); - virtual bool PullOutput( const char * ChannelName, char ** Data, int * Len = NULL ); + virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 ); + virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 ); // Automated Data Input/Output - virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional ); - virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ); + virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Bidirectional ); virtual bool Process() = 0; friend class CApplication; diff --git a/SelectableBare.cpp b/SelectableBare.cpp index 04be540..43deb90 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -319,9 +319,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force ) // Write buffer to Outputs if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) { - Output( Handle->Parent->Channel, Data, Len ); + Output( Handle->Parent->Channel, NULL, true, Data, Len ); } else { - Output( Handle->Channel, Data, Len ); + Output( Handle->Channel, NULL, true, Data, Len ); } // Clear processed bytes from buffer @@ -339,9 +339,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force ) // Write buffer to Outputs if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) { - Output( Handle->Parent->Channel, Data, Len ); + Output( Handle->Parent->Channel, NULL, true, Data, Len ); } else { - Output( Handle->Channel, Data, Len ); + Output( Handle->Channel, NULL, true, Data, Len ); } // Clear processed bytes from buffer @@ -675,7 +675,7 @@ int CSelectableBare::WriteToFD( int FD, const char * Data, int Len, bool Force ) } //--------------------------------------------------------------------------- -int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len ) +int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len ) { TChannel * Channel = NULL; THandle * Handle = NULL; @@ -691,20 +691,20 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len // Get Channel if (!(Channel = GetChannel( ChannelName ))) { // Channel not found - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } else if (!Channel->InputEnabled) { // Channel disabled - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel input disabled", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } // Log event - if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:", - ProcessName, Name, ChannelName ); + if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); // Find Linked handle Handle = FirstHandle; @@ -722,8 +722,8 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len if (!HandleCount) { // Handle not found - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles found", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, No Handles found", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } diff --git a/SelectableCore.h b/SelectableCore.h index 087caf7..cce7bc0 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -291,7 +291,7 @@ public: }; // Function Interface - virtual int Input( const char * ChannelName, const char * Buffer, int BufLen = -1 ); + virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 ); virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual bool Process(); }; From 08fce64629ed29551a3bcf272db7ee6b14bd4a71 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Wed, 5 Jun 2019 19:13:04 +0200 Subject: [PATCH 09/24] Important Update: - FunctionCore - So not set Function JSON "config" param to empty object by default - Change TChannelLink to reference Channel direct - Add Input/Output to TChannelLink - Replace LinkChannel() Bidirectional param with Input/Output param - Update JSON config as well - Implement Channel "Ready" state and events - Remove Input/OutputEnabled parameters and related methods - Remove from JSON config as well - Update AddChannel() method accordingly - Add Ref param to struct TChannel - SelectableCore: - Convert inline ChangeState() to non-inline method - Move ChangeState() to last step in open/close methods - Add Channels in Not Ready state - Change Channel state when Handle state changed - DeviceCore: - Add Channels in Ready state - FileCore: - Add Channel in Not Ready state --- DeviceCore.cpp | 14 +++- FileCore.cpp | 2 +- FunctionCore.cpp | 162 ++++++++++++++++++++++++++------------------- FunctionCore.h | 45 +++++-------- SelectableBare.cpp | 60 ++++++++++++----- SelectableCore.cpp | 53 ++++++++------- SelectableCore.h | 20 ++---- 7 files changed, 202 insertions(+), 154 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 42d86c3..902d5d6 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -68,11 +68,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) // Add Channels if (!(CmdChannel = GetChannel( "Command" ))) - CmdChannel = AddChannel( "Command", true, true ); + CmdChannel = AddChannel( "Command", true ); + else + SetChannelState( CmdChannel, true ); + if (!(DeviceChannel = GetChannel( "Device" ))) - DeviceChannel = AddChannel( "Device", true, true ); + DeviceChannel = AddChannel( "Device", true ); + else + SetChannelState( DeviceChannel, true ); + if (!(EventChannel = GetChannel( "Event" ))) - EventChannel = AddChannel( "Event", true, true ); + EventChannel = AddChannel( "Event", true ); + else + SetChannelState( EventChannel, true ); // Load Polling configuration PollConfig = Config->GetChild( "Polling", true ); diff --git a/FileCore.cpp b/FileCore.cpp index b0a3ac1..8155e5b 100644 --- a/FileCore.cpp +++ b/FileCore.cpp @@ -86,7 +86,7 @@ TFileHandle * CFileCore::AddFile( const char * Name, const char * Path, bool Ap // Create Channel if necessary if (CreateChannel) { - AddChannel( Name ); + AddChannel( Name, false ); } // Set Parameters diff --git a/FunctionCore.cpp b/FunctionCore.cpp index 1fdda9a..c5be8f5 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -54,12 +54,8 @@ CFunctionCore::~CFunctionCore() free( FirstChannel->Ref ); } - // Destroy Linked Outputs + // Destroy Linked Channels while (FirstChannel->FirstLink) { - if (FirstChannel->FirstLink->Name) { - free( FirstChannel->FirstLink->Name ); - free( FirstChannel->FirstLink->Ref ); - } NextLinkedChannel = FirstChannel->FirstLink->Next; delete FirstChannel->FirstLink; FirstChannel->FirstLink = NextLinkedChannel; @@ -103,13 +99,8 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) // Load Channels ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); - while (ChannelConfig) - { - if (ChannelConfig->GetName()) { - AddChannel( ChannelConfig->GetName(), - ChannelConfig->GetChBool( "InputEnabled", true, true ), - ChannelConfig->GetChBool( "OutputEnabled", false, true )); - } + while (ChannelConfig) { + AddChannel( ChannelConfig->GetName(), false ); ChannelConfig = ChannelConfig->GetNextPeer(); } @@ -118,7 +109,6 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); Config = Application->Config->GetChild( ConfigName, true ); } - if (Config->isNull()) Config->SetObject(); return true; } @@ -145,9 +135,10 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig ) { // Get Parameters LinkChannel( Channel->Name, - FunctionMember->GetChStr( "Function" ), - FunctionMember->GetChStr( "Channel" ), - FunctionMember->GetChBool( "Bidirectional" ) ); + FunctionMember->GetChStr( "Function", NULL, true ), + FunctionMember->GetChStr( "Channel", NULL, true ), + FunctionMember->GetChBool( "Input", false, true ), + FunctionMember->GetChBool( "Output", false, true ) ); FunctionMember = FunctionMember->GetNextPeer(); } } @@ -175,7 +166,7 @@ bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel ) } //--------------------------------------------------------------------------- -TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInputEnable, const bool pOutputEnable ) +TChannel * CFunctionCore::AddChannel( const char * ChannelName, bool Ready ) { TChannel ** Channel = NULL; @@ -197,63 +188,106 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu // Set Name (*Channel)->Name = strdup( ChannelName ); + (*Channel)->Ref = (char*)malloc( strlen(Name)+strlen(ChannelName)+2 ); sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName ); + (*Channel)->Ready = Ready; // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created", - ProcessName, Name, ChannelName ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', Ready:%s", + ProcessName, Name, ChannelName, (*Channel)->Ref, (((*Channel)->Ready)? "Yes" : "No") ); } - - // Set parameters - (*Channel)->InputEnabled = pInputEnable; - (*Channel)->OutputEnabled = pOutputEnable; - return *Channel; } //--------------------------------------------------------------------------- -// Automated Data Input/Output -bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Bidirectional ) +bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) { - TChannel * OutChannel = NULL; - CFunctionCore * InFunction = NULL; - TChannel * InChannel = NULL; + TChannelLink * LinkChannel; + + // Validate + if (!Channel) + return false; + + // Update state + Channel->Ready = Ready; + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Channel '%s' - Ready:%s", + ProcessName, Name, Channel->Name, ((Ready)? "Yes" : "No") ); + + // Update linked channels + LinkChannel = Channel->FirstLink; + while (LinkChannel) { + LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, Ready ); + LinkChannel = LinkChannel->Next; + } + + return true; +} +//--------------------------------------------------------------------------- + +bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const bool Ready ) +{ + TChannelLink * LinkChannel; + + if (!Channel) + return false; + if (!(LinkChannel = GetLinkChannel( Channel, SourceRef ))) + return false; + + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Link Channel '%s'-->'%s' - Ready:%s", + ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ((Ready)? "Yes" : "No") ); + + return true; +} +//--------------------------------------------------------------------------- + +// Automated Data Input/Output +bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output ) +{ + TChannel * Channel = NULL; + CFunctionCore * LinkFunction = NULL; + TChannel * LinkChannel = NULL; TChannelLink ** LinkedChannel = NULL; // Check if Channels & Function exist - if (!(OutChannel = GetChannel( ChannelName )) || - !(InFunction = Application->GetFunction( LinkFunctionName )) || - !(InChannel = InFunction->GetChannel( LinkChannelName )) ) { + if (!(Channel = GetChannel( ChannelName )) || + !(LinkFunction = Application->GetFunction( LinkFunctionName )) || + !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) { return false; } // Check if linked Channel exists - LinkedChannel = &(OutChannel->FirstLink); - while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, LinkChannelName ) )) { + LinkedChannel = &(Channel->FirstLink); + while (*LinkedChannel && ((*LinkedChannel)->Channel == LinkChannel)) LinkedChannel = &((*LinkedChannel)->Next); - } - - // Create if not found if (!*LinkedChannel) - { - // Create *LinkedChannel = new TChannelLink; - // Set Parameters - (*LinkedChannel)->Function = InFunction; - (*LinkedChannel)->Name = strdup( LinkChannelName ); - sprintf( (*LinkedChannel)->Ref, "%s/%s", LinkFunctionName, LinkChannelName ); + // Set Parameters + (*LinkedChannel)->Function = LinkFunction; + (*LinkedChannel)->Channel = LinkChannel; + (*LinkedChannel)->Input = Input; + (*LinkedChannel)->Output = Output; - // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s/%s' --> '%s/%s'", - ProcessName, Name, Name, ChannelName, LinkFunctionName, LinkChannelName ); - } + // Log Event + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Linked - '%s'-->'%s' - In:%s, Out:%s", + ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref, ((Input)? "Yes" : "No"), ((Output)? "Yes" : "No") ); - // Link return direction as well - if (Bidirectional) { - return InFunction->LinkChannel( LinkChannelName, Name, ChannelName, false ); - } + // Find Linked channel on remote function + LinkedChannel = &(LinkChannel->FirstLink); + while (*LinkedChannel && ((*LinkedChannel)->Channel == Channel)) + LinkedChannel = &((*LinkedChannel)->Next); + if (!*LinkedChannel) + *LinkedChannel = new TChannelLink; + // Set Parameters + (*LinkedChannel)->Function = this; + (*LinkedChannel)->Channel = Channel; + (*LinkedChannel)->Input = Output; + (*LinkedChannel)->Output = Input; + + // Log Event + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Linked - '%s'-->'%s' - In:%s, Out:%s", + ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref, ((Output)? "Yes" : "No"), ((Input)? "Yes" : "No") ); return true; } //--------------------------------------------------------------------------- @@ -274,9 +308,8 @@ int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, cons ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->InputEnabled) { - // Channel disabled - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'-'%s' - Input rejected, Channel input disabled", + else if (!Channel->Ready) { + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } @@ -316,7 +349,7 @@ int CFunctionCore::Output( const char * ChannelName, const char * TargetRef, con int CFunctionCore::Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat ) { - TChannelLink * OutChannel = NULL; + TChannelLink * LinkChannel = NULL; int TempLen = 0; int OutLen = 0; @@ -325,27 +358,20 @@ int CFunctionCore::Output( const TChannel * Channel, const char * TargetRef, con return 0; } - // Check if enabled - if (!Channel->OutputEnabled) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel output disabled", - ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); - return 0; - } - // Log event - if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:", + if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s'->'%s' - OUT:", ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); // Pass output to all linked inputs if (Len == -1) Len = strlen( Data ); - OutChannel = Channel->FirstLink; - while (OutChannel) { - if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, OutChannel->Ref )) { - TempLen = OutChannel->Function->Input( OutChannel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len ); + LinkChannel = Channel->FirstLink; + while (LinkChannel) { + if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) { + TempLen = LinkChannel->Function->Input( LinkChannel->Channel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len ); OutLen = (TempLen > OutLen)? TempLen : OutLen; } - OutChannel = OutChannel->Next; + LinkChannel = LinkChannel->Next; } // Return processed bytes diff --git a/FunctionCore.h b/FunctionCore.h index a82c1f9..4866372 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -30,10 +30,7 @@ struct SChannel char * Name = NULL; char * Ref = NULL; - TChannelLink * FirstLink = NULL; // List of channels from which input can be received - - bool InputEnabled = NULL; // Can Channel receive input - bool OutputEnabled = NULL; // Can channel receive output + TChannelLink * FirstLink = NULL; // List of channels linked for input/output bool Ready = false; // Channel ready to receive input @@ -44,8 +41,10 @@ struct SChannel struct SChannelLink { CFunctionCore * Function = NULL; - char * Name = NULL; - char * Ref = NULL; + TChannel * Channel = NULL; + + bool Input = false; + bool Output = false; SChannelLink * Next = NULL; }; @@ -84,6 +83,13 @@ protected: Channel = Channel->Next; return Channel; } + inline TChannelLink * GetLinkChannel( TChannel * Channel, const char * LinkRef ) { + if (!Channel || !LinkRef ) return NULL; + SChannelLink * LinkChannel = Channel->FirstLink; + while (LinkChannel && strcmp( LinkRef, LinkChannel->Channel->Ref )) + LinkChannel = LinkChannel->Next; + return LinkChannel; + } // Data Input/Output virtual int Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat = loNone ); @@ -106,34 +112,17 @@ public: inline const char * GetType() { return Type; }; // Manage Channels - virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true ); - inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) { - TChannel * Channel = GetChannel( ChannelName ); - if (!Channel) return false; - Channel->OutputEnabled = pOutputEnable; - return true; - } - inline bool SetChannelInEnable( const char * ChannelName, const bool pInputEnable ) { - TChannel * Channel = GetChannel( ChannelName ); - if (!Channel) return false; - Channel->InputEnabled = pInputEnable; - return true; - } - inline bool isInputEnabled( const char * ChannelName ) { - TChannel * Channel = GetChannel( ChannelName ); - return ((Channel)? Channel->InputEnabled : false); - } - inline bool isOutputEnabled( const char * ChannelName ) { - TChannel * Channel = GetChannel( ChannelName ); - return ((Channel)? Channel->OutputEnabled : false); - } + virtual TChannel * AddChannel( const char * ChannelName, const bool Ready ); + + virtual bool SetChannelState( TChannel * Channel, const bool Ready ); + virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const bool Ready ); // Pushing Data Output -> Input virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 ); virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 ); // Automated Data Input/Output - virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Bidirectional ); + virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output ); virtual bool Process() = 0; friend class CApplication; diff --git a/SelectableBare.cpp b/SelectableBare.cpp index 43deb90..48d3f0b 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -112,7 +112,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh // Create Matching Channel if (CreateChannel) { - (*Handle)->Channel = AddChannel( HandleName ); + (*Handle)->Channel = AddChannel( HandleName, false ); } return *Handle; @@ -218,6 +218,31 @@ bool CSelectableBare::ClearHandle( THandle * Handle ) } //--------------------------------------------------------------------------- +bool CSelectableBare::ChangeState( THandle * Handle, EConnectState State ) +{ + bool Ready; + + // Validate + if (!Handle || (Handle->State == State)) + return false; + + // Set Call back + if (Handle->StateCallback[ (int)State ]) + (Handle->StateCallback[ (int)State ])( this, Handle, State ); + + // Change state + Handle->State = State; + + // Update Channel + if (Handle->Channel) { + Ready = ((Handle->State == csOpen) || (Handle->State == csDataWaiting)); + if (Handle->Channel->Ready != Ready) + SetChannelState( Handle->Channel, Ready ); + } + return true; +} +//--------------------------------------------------------------------------- + bool CSelectableBare::SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback ) { // Validate @@ -356,6 +381,7 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve ) { THandle * NewHandle = NULL; + // Validate if (!Handle || (Handle->Type == ctNone)) { return -1; @@ -391,11 +417,11 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve ) Selector->Add( Handle->FD, true, false, Handle, this ); } - // Set state - ChangeState( Handle, csOpen ); - // Set timer (for re-open or auto-close) SetStartTime( &Handle->LastAction ); + + // Set state + ChangeState( Handle, csOpen ); return (NewHandle)? NewHandle->FD : -1; }; //--------------------------------------------------------------------------- @@ -411,7 +437,16 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen ) // Close Handle Fail = (close( Handle->FD ))? true : false; - ChangeState( Handle, ((Fail)? csFailed : csClosed) ); + + // Remove from Select List + if (!Fail && Selector) { + if (Handle->Type != ctUDPremote) { + Selector->Remove( Handle->FD, true, true ); + } + } + + // Reset FD + Handle->FD = ((Fail)? Handle->FD : -1); // Start timer (for re-open) if (QuickReopen) @@ -423,15 +458,8 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen ) if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s", ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") ); - // Remove from Select List - if (!Fail && Selector) { - if (Handle->Type != ctUDPremote) { - Selector->Remove( Handle->FD, true, true ); - } - } - - // Reset FD - Handle->FD = ((Fail)? Handle->FD : -1); + // Set State + ChangeState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- @@ -695,9 +723,9 @@ int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, co ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->InputEnabled) { + else if (!Channel->Ready) { // Channel disabled - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel input disabled", + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 1f9537b..97faf75 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -632,6 +632,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) // Set state close( Handle->FD ); Handle->FD = -1; + ChangeState( Handle, csFailed ); return NULL; }; @@ -646,6 +647,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) // Set state close( Handle->FD ); Handle->FD = -1; + ChangeState( Handle, csFailed ); return NULL; }; @@ -729,11 +731,10 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) // Close socket close( Handle->FD ); - ChangeState( Handle, csFailed ); + Handle->FD = -1; Handle->AddressFailed = true; - // Reset Handle - Handle->FD = -1; + ChangeState( Handle, csFailed ); return NULL; } } @@ -978,11 +979,13 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to bind UDP socket [%s:%s] (%s)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); - // Set state + // Close handle close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); Handle->AddressFailed = true; + + // Change state + ChangeState( Handle, csFailed ); return NULL; }; @@ -1173,11 +1176,12 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to bind TCP Server socket [%s:%s] (%s)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); - // Set state + // Close handle close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); Handle->AddressFailed = true; + + ChangeState( Handle, csFailed ); return NULL; }; @@ -1188,11 +1192,12 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to listen on TCP Server socket [%s:%s] (%s)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); - // Set state + // Close handle close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); Handle->AddressFailed = true; + + ChangeState( Handle, csFailed ); return NULL; }; @@ -1362,9 +1367,10 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); - // Set State + // Close handle close( Handle->FD ); Handle->FD = -1; + ChangeState( Handle, csFailed ); return NULL; } @@ -1413,11 +1419,10 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso // Close socket close( Handle->FD ); - ChangeState( Handle, csFailed ); + Handle->FD = -1; Handle->AddressFailed = true; - // Reset Handle - Handle->FD = -1; + ChangeState( Handle, csFailed ); return NULL; } } @@ -1515,7 +1520,16 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen ) } else { Fail = (close( Handle->FD ))? true : false; } - ChangeState( Handle, ((Fail)? csFailed : csClosed) ); + + // Remove from Select List + if (!Fail && Selector) { + if (Handle->Type != ctUDPremote) { + Selector->Remove( Handle->FD, true, true ); + } + } + + // Reset FD + Handle->FD = ((Fail)? Handle->FD : -1); // Start timer (for re-open) if (QuickReopen) @@ -1599,15 +1613,8 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen ) break; }; - // Remove from Select List - if (!Fail && Selector) { - if (Handle->Type != ctUDPremote) { - Selector->Remove( Handle->FD, true, true ); - } - } - - // Reset FD - Handle->FD = ((Fail)? Handle->FD : -1); + // Change State + ChangeState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- diff --git a/SelectableCore.h b/SelectableCore.h index cce7bc0..8e7f51c 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -194,6 +194,7 @@ protected: // Managing File Handles bool RemoveHandle( THandle * Handle ); bool DestroyHandle( THandle * Handle ); + bool ChangeState( THandle * Handle, EConnectState State ); // Get Parameters inline int GetFD( const char * HandleName ) { @@ -201,15 +202,6 @@ protected: return ((Handle)? Handle->FD : -1); }; - // General fucntions - inline bool ChangeState( THandle * Handle, EConnectState State ) { - if (!Handle || (Handle->State == State)) return false; - if (Handle->StateCallback[ (int)State ]) - (Handle->StateCallback[ (int)State ])( this, Handle, State ); - Handle->State = State; - return true; - } - // Mutual Operations int ReadFromFD( int FD, char * Data, int MaxLen ); int WriteToFD( int FD, const char * Data, int Len, bool Force ); @@ -230,19 +222,17 @@ public: virtual ~CSelectableBare(); // Configuration - virtual bool Init( CDataMember * FunctionConfig ) = 0; + virtual bool Init( CDataMember * FunctionConfig ) = 0; // Finding Handles - inline THandle * GetHandle( const char * HandleName ) - { + inline THandle * GetHandle( const char * HandleName ) { if (!HandleName) return NULL; THandle * Handle = FirstHandle; while ( Handle && strcmp( HandleName, Handle->Name )) Handle = Handle->Next; return Handle; } - inline THandle * GetHandle( int FD ) - { + inline THandle * GetHandle( int FD ) { if (FD < 0) return NULL; THandle * Handle = FirstHandle; while ( Handle && (FD != Handle->FD)) @@ -263,7 +253,7 @@ public: bool ClearHandle( THandle * Handle ); // FD Operations - virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0; + virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0; virtual bool Close( THandle * Handle, bool QuickReopen ); virtual bool Read( THandle * Handle ); virtual bool Write( THandle * Handle ); From bde14a13da5eb73f2f37d0d403e7d31fbb273d2e Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 9 Jun 2019 22:05:27 +0200 Subject: [PATCH 10/24] Major Update: - FunctionCore - Replace Channel->Ready with Channel->State (off/waiting/ready) - Add Function reference to Handle - SelectableBare/Core: - Implement async address resolve with event handling - Create ResolveHandler() signal handler (friend) function - Change Create/Remove/DestroyHandle() methods to virtual methods - Move socket specific code to SelectableCore - Rename ChangeState() to virtual HandleState() - Move ClearHandle() from SelectableBare -> SelectableCore - Implement new/delete from THandle - Set max TCP SYN count on connect --- DeviceCore.cpp | 12 +- FileCore.cpp | 2 +- FunctionCore.cpp | 32 ++--- FunctionCore.h | 14 +- SelectableBare.cpp | 82 +++--------- SelectableCore.cpp | 324 +++++++++++++++++++++++++++++++++++++-------- SelectableCore.h | 42 ++++-- SignalCore.cpp | 18 +-- 8 files changed, 360 insertions(+), 166 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 902d5d6..d648dae 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -68,19 +68,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) // Add Channels if (!(CmdChannel = GetChannel( "Command" ))) - CmdChannel = AddChannel( "Command", true ); + CmdChannel = AddChannel( "Command", CH_ready ); else - SetChannelState( CmdChannel, true ); + SetChannelState( CmdChannel, CH_ready ); if (!(DeviceChannel = GetChannel( "Device" ))) - DeviceChannel = AddChannel( "Device", true ); + DeviceChannel = AddChannel( "Device", CH_ready ); else - SetChannelState( DeviceChannel, true ); + SetChannelState( DeviceChannel, CH_ready ); if (!(EventChannel = GetChannel( "Event" ))) - EventChannel = AddChannel( "Event", true ); + EventChannel = AddChannel( "Event", CH_ready ); else - SetChannelState( EventChannel, true ); + SetChannelState( EventChannel, CH_ready ); // Load Polling configuration PollConfig = Config->GetChild( "Polling", true ); diff --git a/FileCore.cpp b/FileCore.cpp index 8155e5b..1c0aa95 100644 --- a/FileCore.cpp +++ b/FileCore.cpp @@ -86,7 +86,7 @@ TFileHandle * CFileCore::AddFile( const char * Name, const char * Path, bool Ap // Create Channel if necessary if (CreateChannel) { - AddChannel( Name, false ); + AddChannel( Name, CH_ready ); } // Set Parameters diff --git a/FunctionCore.cpp b/FunctionCore.cpp index c5be8f5..6a3450f 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -100,7 +100,7 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) // Load Channels ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); while (ChannelConfig) { - AddChannel( ChannelConfig->GetName(), false ); + AddChannel( ChannelConfig->GetName(), CH_off ); ChannelConfig = ChannelConfig->GetNextPeer(); } @@ -166,7 +166,7 @@ bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel ) } //--------------------------------------------------------------------------- -TChannel * CFunctionCore::AddChannel( const char * ChannelName, bool Ready ) +TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelState State ) { TChannel ** Channel = NULL; @@ -190,17 +190,17 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, bool Ready ) (*Channel)->Name = strdup( ChannelName ); (*Channel)->Ref = (char*)malloc( strlen(Name)+strlen(ChannelName)+2 ); sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName ); - (*Channel)->Ready = Ready; + (*Channel)->State = State; // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', Ready:%s", - ProcessName, Name, ChannelName, (*Channel)->Ref, (((*Channel)->Ready)? "Yes" : "No") ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', State:%s", + ProcessName, Name, ChannelName, (*Channel)->Ref, ChannelStateName[(*Channel)->State] ); } return *Channel; } //--------------------------------------------------------------------------- -bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) +bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState State ) { TChannelLink * LinkChannel; @@ -209,14 +209,14 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) return false; // Update state - Channel->Ready = Ready; - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Channel '%s' - Ready:%s", - ProcessName, Name, Channel->Name, ((Ready)? "Yes" : "No") ); + Channel->State = State; + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Channel '%s' - State:%s", + ProcessName, Name, Channel->Name, ChannelStateName[State] ); // Update linked channels LinkChannel = Channel->FirstLink; while (LinkChannel) { - LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, Ready ); + LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, State ); LinkChannel = LinkChannel->Next; } @@ -224,7 +224,7 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) } //--------------------------------------------------------------------------- -bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const bool Ready ) +bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState State ) { TChannelLink * LinkChannel; @@ -233,8 +233,8 @@ bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRe if (!(LinkChannel = GetLinkChannel( Channel, SourceRef ))) return false; - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Link Channel '%s'-->'%s' - Ready:%s", - ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ((Ready)? "Yes" : "No") ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Link Channel '%s'-->'%s' - State:%s", + ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ChannelStateName[State] ); return true; } @@ -308,9 +308,9 @@ int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, cons ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->Ready) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", - ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); + else if (!Channel->State) { + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->State] ); return 0; } diff --git a/FunctionCore.h b/FunctionCore.h index 4866372..72227e0 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -17,6 +17,12 @@ //--------------------------------------------------------------------------- +// Enumarate Types +typedef enum { CH_off = 0, CH_wait = 1, CH_ready = 2 } EChannelState; +const char ChannelStateName[][15] = { "Off", "Waiting", "Ready" }; + +//--------------------------------------------------------------------------- + // Preview typedef struct SChannel TChannel; typedef struct SChannelLink TChannelLink; @@ -32,7 +38,7 @@ struct SChannel TChannelLink * FirstLink = NULL; // List of channels linked for input/output - bool Ready = false; // Channel ready to receive input + EChannelState State = CH_off; // Channel ready to receive input TChannel * Next = NULL; }; @@ -112,10 +118,10 @@ public: inline const char * GetType() { return Type; }; // Manage Channels - virtual TChannel * AddChannel( const char * ChannelName, const bool Ready ); + virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State ); - virtual bool SetChannelState( TChannel * Channel, const bool Ready ); - virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const bool Ready ); + virtual bool SetChannelState( TChannel * Channel, const EChannelState State ); + virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState State ); // Pushing Data Output -> Input virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 ); diff --git a/SelectableBare.cpp b/SelectableBare.cpp index 48d3f0b..b167ab8 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -94,7 +94,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh if (!*Handle) { // Create File handle at end of list - *Handle = (THandle*)calloc( 1, sizeof(THandle) ); + *Handle = new THandle; // Set name if (HandleName) { @@ -103,7 +103,8 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh } // Set File Descriptor - (*Handle)->FD = -1; + (*Handle)->Function = this; + (*Handle)->FD = -1; // Log event if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created", @@ -112,7 +113,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh // Create Matching Channel if (CreateChannel) { - (*Handle)->Channel = AddChannel( HandleName, false ); + (*Handle)->Channel = AddChannel( HandleName, CH_off ); } return *Handle; @@ -159,68 +160,16 @@ bool CSelectableBare::DestroyHandle( THandle * Handle ) free( Handle->Name ); if (Handle->Path) free( Handle->Path ); - if (Handle->HostName) - free( Handle->HostName ); - if (Handle->PortName) - free( Handle->PortName ); - if (Handle->AddressInfo) - freeaddrinfo( Handle->AddressList ); - - // Destroy Buffers - if (Handle->InBuffer) - delete Handle->InBuffer; - if (Handle->OutBuffer) - delete Handle->OutBuffer; - - // Clear Input Markers - if (Handle->InMarker) - free( Handle->InMarker ); // Destroy Pointer - free( Handle ); + delete Handle; return true; } //--------------------------------------------------------------------------- -bool CSelectableBare::ClearHandle( THandle * Handle ) +bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) { - // Validate - if (!Handle) { - return false; - } - - // Reset Type related parameters - if (Handle->Path) { - free( Handle->Path ); - Handle->Path = NULL; - } - if (Handle->HostName) { - free( Handle->HostName ); - Handle->HostName = NULL; - } - if (Handle->PortName) { - free( Handle->PortName ); - Handle->PortName = NULL; - } - if (Handle->AddressList) { - freeaddrinfo( Handle->AddressList ); - Handle->AddressList = NULL; - Handle->AddressInfo = NULL; - } - - // Reset Parameters - Handle->Type = ctNone; - - // Log event - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", - ProcessName, Name, Handle->Name ); - return true; -} -//--------------------------------------------------------------------------- - -bool CSelectableBare::ChangeState( THandle * Handle, EConnectState State ) -{ - bool Ready; + EChannelState ChannelState = CH_off; // Validate if (!Handle || (Handle->State == State)) @@ -235,9 +184,14 @@ bool CSelectableBare::ChangeState( THandle * Handle, EConnectState State ) // Update Channel if (Handle->Channel) { - Ready = ((Handle->State == csOpen) || (Handle->State == csDataWaiting)); - if (Handle->Channel->Ready != Ready) - SetChannelState( Handle->Channel, Ready ); + if ((Handle->State == csOpenRequest) || (Handle->State == csWaitingtoOpen)) + ChannelState = CH_wait; + else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting)) + ChannelState = CH_ready; + else + ChannelState = CH_off; + if (Handle->Channel->State != ChannelState) + SetChannelState( Handle->Channel, ChannelState ); } return true; } @@ -421,7 +375,7 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve ) SetStartTime( &Handle->LastAction ); // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return (NewHandle)? NewHandle->FD : -1; }; //--------------------------------------------------------------------------- @@ -459,7 +413,7 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen ) ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") ); // Set State - ChangeState( Handle, ((Fail)? csFailed : csClosed) ); + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- @@ -723,7 +677,7 @@ int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, co ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->Ready) { + else if (Channel->State != CH_ready) { // Channel disabled if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 97faf75..0a5110f 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -40,13 +40,62 @@ CFunctionCore * NewSelectableCore( const char * Name ) { } //--------------------------------------------------------------------------- +// Resolve action handlder +void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ) +{ + TResolveReq * ResolveReq; + THandle * Handle; + + // Validate signal + if ((SignalInfo->si_code != SI_ASYNCNL) || + (SignalInfo->si_signo != SIGRTMIN)) + return; + + // Get Handle & Request + ResolveReq = (TResolveReq*)(SignalInfo->si_value.sival_ptr); + Handle = ResolveReq->Handle; + + ((CSelectableCore*)Handle->Function)->HandleResolve( Handle ); +} +//--------------------------------------------------------------------------- + CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CSelectableBare( pName, pType ) { + // Configure resolve signal handler + ResolveAct.sa_sigaction = &ResolveHandler; + sigemptyset( &ResolveAct.sa_mask ); + ResolveAct.sa_flags = SA_SIGINFO; + + sigaction( SIGRTMIN, &ResolveAct, NULL ); } //--------------------------------------------------------------------------- CSelectableCore::~CSelectableCore() { + THandle * NextHandle = NULL; + bool Result; + + // Destroy File Handles + while (FirstHandle) + { + // Close active resolve request + if (FirstHandle->Resolving && FirstHandle->ResolveReq) { + if ((Result = gai_cancel( FirstHandle->ResolveReq->Request )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)", + ProcessName, Name, FirstHandle->Name, FirstHandle->HostName, FirstHandle->PortName, gai_strerror(Result) ); + DestroyResolveReq( FirstHandle, true ); + HandleState( FirstHandle, csFailed ); + } + } + + // Close handle if open + if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) + Close( FirstHandle, false ); + + NextHandle = FirstHandle->Next; + DestroyHandle( FirstHandle ); + FirstHandle = NextHandle; + } } //--------------------------------------------------------------------------- @@ -227,6 +276,87 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) } //--------------------------------------------------------------------------- +bool CSelectableCore::DestroyHandle( THandle * Handle ) +{ + int Result; + + // Validate Handle + if (!Handle) + return false; + + // Destroy Resolve request + if (Handle->Resolving && Handle->ResolveReq) { + if ((Result = gai_cancel( Handle->ResolveReq->Request )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); + } + DestroyResolveReq( Handle, true ); + } + + // Clear parameters + if (Handle->Name) + free( Handle->Name ); + if (Handle->Path) + free( Handle->Path ); + if (Handle->HostName) + free( Handle->HostName ); + if (Handle->PortName) + free( Handle->PortName ); + if (Handle->AddressList) + freeaddrinfo( Handle->AddressList ); + + // Destroy Buffers + if (Handle->InBuffer) + delete Handle->InBuffer; + if (Handle->OutBuffer) + delete Handle->OutBuffer; + + // Clear Input Markers + if (Handle->InMarker) + free( Handle->InMarker ); + + // Destroy Pointer + delete Handle; + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::ClearHandle( THandle * Handle ) +{ + // Validate + if (!Handle) { + return false; + } + + // Reset Type related parameters + if (Handle->Path) { + free( Handle->Path ); + Handle->Path = NULL; + } + if (Handle->HostName) { + free( Handle->HostName ); + Handle->HostName = NULL; + } + if (Handle->PortName) { + free( Handle->PortName ); + Handle->PortName = NULL; + } + if (Handle->AddressList) { + freeaddrinfo( Handle->AddressList ); + Handle->AddressList = NULL; + Handle->AddressInfo = NULL; + } + + // Reset Parameters + Handle->Type = ctNone; + + // Log event + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", + ProcessName, Name, Handle->Name ); + return true; +} +//--------------------------------------------------------------------------- + bool CSelectableCore::SetSerialHandle( THandle * Handle, const char * FileName ) { // Validate @@ -427,7 +557,7 @@ THandle * CSelectableCore::OpenSerialPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -470,7 +600,7 @@ THandle * CSelectableCore::OpenLinePrinterPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -572,7 +702,7 @@ THandle * CSelectableCore::OpenForkPipe( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -596,7 +726,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -608,7 +738,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -633,7 +763,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -648,7 +778,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -662,7 +792,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -688,7 +818,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -715,7 +845,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -734,7 +864,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } } @@ -749,7 +879,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -846,7 +976,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -856,12 +986,17 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) { - struct addrinfo hints; - int result; + struct addrinfo * Hints; + TResolveReq * ResolveReq; + sigevent ResolveEvt; + int Result; + + // Ignore if busy resolving + if (Handle->Resolving) + return false; // Check if resolved address available - if (Handle->AddressInfo) - { + if (Handle->AddressInfo) { // Return if address still valid if (!Handle->AddressFailed) return true; @@ -892,47 +1027,117 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) } // Set address specification - memset( &hints, 0, sizeof hints ); + Hints = (struct addrinfo*)calloc( 1, sizeof(struct addrinfo) ); if ((Handle->Type == ctTCPserver) || (Handle->Type == ctTCPclient)) { - hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 - hints.ai_socktype = SOCK_STREAM; + Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 + Hints->ai_socktype = SOCK_STREAM; } else { - hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 - hints.ai_socktype = SOCK_DGRAM; + Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 + Hints->ai_socktype = SOCK_DGRAM; } + // Create request data + ResolveReq = new TResolveReq; + Handle->ResolveReq = ResolveReq; + + ResolveReq->Handle = Handle; + ResolveReq->Request = (gaicb*)calloc( 1, sizeof(gaicb) ); + + // DNS request / reply structure + ResolveReq->Request->ar_name = Handle->HostName; + ResolveReq->Request->ar_service = Handle->PortName; + ResolveReq->Request->ar_request = Hints; + ResolveReq->Request->ar_result = NULL; + + // Configure signal event + ResolveEvt.sigev_notify = SIGEV_SIGNAL; + ResolveEvt.sigev_signo = SIGRTMIN; + ResolveEvt.sigev_value.sival_ptr = ResolveReq; + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Resolving Host name [%s:%s]...", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); // Should address be resolved later during process() - if (DelayResolve) - { + if (DelayResolve) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Delay resolving of Host Name [%s:%s]", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); - ChangeState( Handle, csOpenRequest ); + + HandleState( Handle, csOpenRequest ); return false; } // Resolve Host & Port Names - if ((result = getaddrinfo( Handle->HostName, Handle->PortName, &hints, &(Handle->AddressList))) != 0) - { - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)", - ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) ); - ChangeState( Handle, csFailed ); + Handle->Resolving = true; + if ((Result = getaddrinfo_a( GAI_NOWAIT, &(Handle->ResolveReq->Request), 1, &ResolveEvt )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); + DestroyResolveReq( Handle, true ); + + HandleState( Handle, csFailed ); + return false; + } + return false; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::DestroyResolveReq( THandle * Handle, bool DestroyResult ) +{ + // Validate + if (!Handle || !Handle->ResolveReq) + return false; + + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Destroying resolve request [%s:%s]", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); + + // Destroy + if (DestroyResult) { + if (Handle->ResolveReq->Request->ar_result) + freeaddrinfo( Handle->ResolveReq->Request->ar_result ); + } + if (Handle->ResolveReq->Request->ar_request) + free( (void*)Handle->ResolveReq->Request->ar_request ); + if (Handle->ResolveReq->Request) + free( Handle->ResolveReq->Request ); + if (Handle->ResolveReq) + delete Handle->ResolveReq; + + // Reset request + Handle->ResolveReq = NULL; + Handle->Resolving = false; + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::HandleResolve( THandle * Handle ) +{ + bool Result; + + // Validate result + if ((Result = gai_error( Handle->ResolveReq->Request )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); + DestroyResolveReq( Handle, true ); + + HandleState( Handle, csFailed ); return false; } - // Select first address, skip "0.0.0.0" + // Read result + Handle->AddressList = Handle->ResolveReq->Request->ar_result; Handle->AddressInfo = Handle->AddressList; + + // Select first address, skip "0.0.0.0" if (!strcmp( inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr), "0.0.0.0" )) Handle->AddressInfo = Handle->AddressInfo->ai_next; + if (!Handle->AddressInfo) { - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)", - ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) ); + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (No Result)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); freeaddrinfo( Handle->AddressList ); Handle->AddressList = NULL; Handle->AddressInfo = NULL; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return false; } @@ -941,6 +1146,9 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr), ntohs(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port) ); + + // Destroy request + DestroyResolveReq( Handle, false ); return true; } //--------------------------------------------------------------------------- @@ -964,7 +1172,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -985,7 +1193,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso Handle->AddressFailed = true; // Change state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -999,7 +1207,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1081,7 +1289,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set Status - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1098,7 +1306,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1133,7 +1341,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1146,7 +1354,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -1161,7 +1369,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -1181,7 +1389,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1197,7 +1405,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1211,7 +1419,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1313,7 +1521,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->HostName ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -1324,10 +1532,11 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayResolve ) { // Socket options - int KeepAlive_opt = 1; - int TCPidle_opt = 5; - int TCPcnt_opt = 3; - int TCPint_opt = 2; + int KeepAlive_opt = 1; // Enable/disable keep alive + int TCPidle_opt = 5; // Idle time on socket before sending first keep alive signal + int TCPint_opt = 2; // Interval between keep alive signals + int TCPcnt_opt = 3; // No of missed keep alive response before connection fail + int TCPsyn_opt = 3; // Max SYN (connect retries) before open fails // Check state if (Handle->State == csOpen) { @@ -1349,7 +1558,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set Status - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1361,7 +1570,8 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso if ((setsockopt( Handle->FD, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || - (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) ) + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_SYNCNT, &TCPsyn_opt, sizeof(TCPsyn_opt)) == -1) ) { // Log Event if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)", @@ -1371,7 +1581,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } } @@ -1388,7 +1598,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EALREADY)) @@ -1403,7 +1613,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -1422,7 +1632,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } } @@ -1614,7 +1824,7 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen ) }; // Change State - ChangeState( Handle, ((Fail)? csFailed : csClosed) ); + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- diff --git a/SelectableCore.h b/SelectableCore.h index 8e7f51c..98490a9 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -10,6 +10,8 @@ // Standard C/C++ Libraries #include +#include +#include // redA Libraries #include "FunctionCore.h" @@ -44,13 +46,14 @@ const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "O // Previews typedef struct SSelectHandle TSelectHandle; typedef struct SHandle THandle; +typedef struct SResolveReq TResolveReq; class CSelect; class CSelectableBare; class CSelectableCore; // Callback function for handle events -typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState State ); +typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState OldState ); //--------------------------------------------------------------------------- @@ -68,7 +71,6 @@ struct SSelectHandle { // List TSelectHandle * Next = NULL; }; - //--------------------------------------------------------------------------- // List or Handles for Selectable Function Object @@ -76,6 +78,7 @@ struct SHandle { // Description char * Name = NULL; EConnectType Type = ctNone; + CSelectableBare * Function = NULL; // State int FD = -1; @@ -103,7 +106,10 @@ struct SHandle { struct addrinfo * AddressInfo = NULL; // Current selected IP Address bool AddressFailed = false; // Indicate failure to connect to address short Queue = 2; // Max waiting connections + long ResolveDelay = 0; // Delay before resolving hostname via DNS + TResolveReq * ResolveReq = NULL; // DNS resolve request + bool Resolving = false; // Busy resolving address // Serial Port config bool SerialConfig = false; @@ -132,6 +138,16 @@ struct SHandle { THandle * Parent = NULL; THandle * Next = NULL; }; +//--------------------------------------------------------------------------- + +struct SResolveReq { + THandle * Handle = NULL; + gaicb * Request = NULL; +}; +//--------------------------------------------------------------------------- + +// Resolving +void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ); //--------------------------------------------------------------------------- @@ -192,9 +208,9 @@ protected: CSelect * Selector = NULL; // Managing File Handles - bool RemoveHandle( THandle * Handle ); - bool DestroyHandle( THandle * Handle ); - bool ChangeState( THandle * Handle, EConnectState State ); + virtual bool RemoveHandle( THandle * Handle ); + virtual bool DestroyHandle( THandle * Handle ); + virtual bool HandleState( THandle * Handle, EConnectState State ); // Get Parameters inline int GetFD( const char * HandleName ) { @@ -241,7 +257,7 @@ public: } // General port parameters - THandle * CreateHandle( const char * HandleName, bool CreateChannel ); + virtual THandle * CreateHandle( const char * HandleName, bool CreateChannel ); virtual CDataMember * GetHandleAddress( THandle * Handle, const char * HandleRef ); bool SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback ); @@ -249,9 +265,6 @@ public: bool SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen ); bool SetOutBuffer( THandle * Handle, int OutBufSize ); - // Specific port parameters - bool ClearHandle( THandle * Handle ); - // FD Operations virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0; virtual bool Close( THandle * Handle, bool QuickReopen ); @@ -291,6 +304,8 @@ public: class CSelectableCore : public CSelectableBare { protected: + struct sigaction ResolveAct; + // Port Operations THandle * OpenSerialPort( THandle * Handle ); bool WriteSerialConfig( THandle * Handle ); @@ -306,6 +321,11 @@ protected: // Socket Operations bool ResolveAddress( THandle * Handle, bool DelayResolve ); + bool HandleResolve( THandle * Handle ); + bool DestroyResolveReq( THandle * Handle, bool DestroyResult ); + + // Managing File Handles + virtual bool DestroyHandle( THandle * Handle ); THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve ); THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort ); @@ -330,6 +350,8 @@ public: virtual bool Init( CDataMember * FunctionConfig ); // Specific port parameters + bool ClearHandle( THandle * Handle ); + bool SetSerialHandle( THandle * Handle, const char * FileName ); bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait ); bool SetLinePrinterHandle( THandle * Handle, const char * FileName ); @@ -346,6 +368,8 @@ public: // Function Interface virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual bool Process(); + + friend void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ); }; //--------------------------------------------------------------------------- diff --git a/SignalCore.cpp b/SignalCore.cpp index 748304b..7c8654b 100644 --- a/SignalCore.cpp +++ b/SignalCore.cpp @@ -41,21 +41,21 @@ void ConfigureSignalHandlers() sigemptyset( &TermAct.sa_mask ); TermAct.sa_flags = SA_RESTART; - sigaction( SIGHUP, &TermAct, 0 ); - sigaction( SIGINT, &TermAct, 0 ); - sigaction( SIGQUIT, &TermAct, 0 ); - sigaction( SIGTERM, &TermAct, 0 ); - sigaction( SIGTSTP, &TermAct, 0 ); + sigaction( SIGHUP, &TermAct, NULL ); + sigaction( SIGINT, &TermAct, NULL ); + sigaction( SIGQUIT, &TermAct, NULL ); + sigaction( SIGTERM, &TermAct, NULL ); + sigaction( SIGTSTP, &TermAct, NULL ); // Signals for immediate termination AbortAct.sa_handler = SignalAbort; sigemptyset( &AbortAct.sa_mask ); AbortAct.sa_flags = 0; - sigaction( SIGABRT, &AbortAct, 0 ); - sigaction( SIGFPE, &AbortAct, 0 ); - sigaction( SIGILL, &AbortAct, 0 ); - sigaction( SIGSEGV, &AbortAct, 0 ); + sigaction( SIGABRT, &AbortAct, NULL ); + sigaction( SIGFPE, &AbortAct, NULL ); + sigaction( SIGILL, &AbortAct, NULL ); + sigaction( SIGSEGV, &AbortAct, NULL ); } //--------------------------------------------------------------------------- From 7787da51193a24d616c19ee50efbf16080d9385c Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 10 Jun 2019 10:44:51 +0200 Subject: [PATCH 11/24] Important Update: - Complete Async resolve: - Remove Resolving param from THandle - Rename state csResolving -> csPreparing - Added handle state csPrepared, to indicated resolve complete - Open handle if state = csPrepared - Remove Resolve delay (not required since async resolve) - remove from JSON config as well --- SelectableBare.cpp | 36 +++++++----------- SelectableCore.cpp | 95 +++++++++++++++++++--------------------------- SelectableCore.h | 26 ++++++------- 3 files changed, 64 insertions(+), 93 deletions(-) diff --git a/SelectableBare.cpp b/SelectableBare.cpp index b167ab8..265e691 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -184,7 +184,7 @@ bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) // Update Channel if (Handle->Channel) { - if ((Handle->State == csOpenRequest) || (Handle->State == csWaitingtoOpen)) + if ((Handle->State == csPreparing) || (Handle->State == csPrepared) || (Handle->State == csWaitingtoOpen)) ChannelState = CH_wait; else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting)) ChannelState = CH_ready; @@ -331,7 +331,7 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force ) } //--------------------------------------------------------------------------- -int CSelectableBare::Open( THandle * Handle, bool DelayResolve ) +int CSelectableBare::Open( THandle * Handle ) { THandle * NewHandle = NULL; @@ -513,7 +513,7 @@ bool CSelectableBare::Write( THandle * Handle ) else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { // Attempt to re-open port - Open( Handle, true ); + Open( Handle ); } } @@ -731,11 +731,11 @@ int CSelectableBare::OutputHandle( THandle * Handle, const char * Data, int Len else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { // Complete opening process - Open( Handle, true ); + Open( Handle ); // Check if Handle is open - if (Handle->State == csOpenRequest) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle", + if ((Handle->State == csPreparing) || (Handle->State == csPrepared)) { + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Preparing (auto-managed) Handle", ProcessName, Name, Handle->Name ); return 0; } @@ -812,27 +812,21 @@ bool CSelectableBare::Process() while (Handle) { // Auto manage handles - if ((Handle->State == csOpenRequest)) - { - // Resolve then open socket - if (Timeout( Handle->LastAction, Handle->ResolveDelay )) { - Open( Handle, false ); - } + if (Handle->State == csPrepared) { + // Proceed to open + Open( Handle ); } - else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) ) - { + else if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) { // Try to re-open port after delay if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { - Open( Handle, false ); + Open( Handle ); } } // Check Input buffers - if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) - { + if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) { // Check duration since last PortIn - if (Timeout( Handle->InStart, Handle->InTimeout )) - { + if (Timeout( Handle->InStart, Handle->InTimeout )) { // Process Input ProcessInputBuffer( Handle, true ); @@ -842,14 +836,12 @@ bool CSelectableBare::Process() } // Check for auto close (but not on servers) - if ((Handle->State == csOpen) && (Handle->Type != ctTCPserver) && (Handle->Type != ctUNIXserver) && Handle->AutoManage && !Handle->Persistent) - { + if ((Handle->State == csOpen) && Handle->AutoManage && !Handle->Persistent) { // Close port after timeout if (Timeout( Handle->LastAction, Handle->CloseTimeout )) { Close( Handle, true ); } } - Handle = Handle->Next; } return true; diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 0a5110f..8561774 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -79,7 +79,7 @@ CSelectableCore::~CSelectableCore() while (FirstHandle) { // Close active resolve request - if (FirstHandle->Resolving && FirstHandle->ResolveReq) { + if (FirstHandle->ResolveReq) { if ((Result = gai_cancel( FirstHandle->ResolveReq->Request )) != 0) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)", ProcessName, Name, FirstHandle->Name, FirstHandle->HostName, FirstHandle->PortName, gai_strerror(Result) ); @@ -114,7 +114,6 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) short Parity; short FlowCtrl; short Queue; - long Delay; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) @@ -210,8 +209,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); - SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0, Delay ); + SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0 ); } else if (!strcasecmp( Type, "UDPclient" )) { @@ -222,8 +220,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); - SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0, Delay ); + SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0 ); } else if (!strcasecmp( Type, "TCPserver" )) { @@ -234,9 +231,8 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true ); - SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Queue, Delay ); + SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Queue ); } else if (!strcasecmp( Type, "TCPclient" )) { @@ -247,8 +243,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); - SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0, Delay ); + SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0 ); } else if (!strcasecmp( Type, "ForkPipe" )) { Address = (char*)HandleConfig->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value @@ -285,7 +280,7 @@ bool CSelectableCore::DestroyHandle( THandle * Handle ) return false; // Destroy Resolve request - if (Handle->Resolving && Handle->ResolveReq) { + if (Handle->ResolveReq) { if ((Result = gai_cancel( Handle->ResolveReq->Request )) != 0) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); @@ -467,7 +462,7 @@ bool CSelectableCore::SetUnixHandle( THandle * Handle, EConnectType Type, const } //--------------------------------------------------------------------------- -bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay ) +bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue ) { // Validate if (!Handle || !HostName || !PortName || @@ -478,7 +473,6 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con // Set Type Handle->Type = Type; - Handle->ResolveDelay = ResolveDelay; // Clear HostName & Port Name if (Handle->HostName) @@ -984,7 +978,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) } //--------------------------------------------------------------------------- -bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) +bool CSelectableCore::ResolveAddress( THandle * Handle ) { struct addrinfo * Hints; TResolveReq * ResolveReq; @@ -992,7 +986,7 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) int Result; // Ignore if busy resolving - if (Handle->Resolving) + if (Handle->State == csPreparing) return false; // Check if resolved address available @@ -1057,17 +1051,9 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Resolving Host name [%s:%s]...", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); - // Should address be resolved later during process() - if (DelayResolve) { - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Delay resolving of Host Name [%s:%s]", - ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); - - HandleState( Handle, csOpenRequest ); - return false; - } - // Resolve Host & Port Names - Handle->Resolving = true; + HandleState( Handle, csPreparing ); + if ((Result = getaddrinfo_a( GAI_NOWAIT, &(Handle->ResolveReq->Request), 1, &ResolveEvt )) != 0) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); @@ -1086,9 +1072,6 @@ bool CSelectableCore::DestroyResolveReq( THandle * Handle, bool DestroyResult ) if (!Handle || !Handle->ResolveReq) return false; - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Destroying resolve request [%s:%s]", - ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); - // Destroy if (DestroyResult) { if (Handle->ResolveReq->Request->ar_result) @@ -1103,7 +1086,6 @@ bool CSelectableCore::DestroyResolveReq( THandle * Handle, bool DestroyResult ) // Reset request Handle->ResolveReq = NULL; - Handle->Resolving = false; return true; } //--------------------------------------------------------------------------- @@ -1149,11 +1131,12 @@ bool CSelectableCore::HandleResolve( THandle * Handle ) // Destroy request DestroyResolveReq( Handle, false ); + HandleState( Handle, csPrepared ); return true; } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle ) { // Validate Handle if (Handle->Type != ctUDPserver) { @@ -1161,7 +1144,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso } // Resolve Host & Port Names - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create socket @@ -1237,7 +1220,7 @@ THandle * CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientA // Create Remote Client Handle sprintf( ClientName, "%s-%d", Handle->Name, ClientCount ); *RemoteClient = CreateHandle( ClientName, false ); - if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0, 0 )) { + if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0 )) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - UDP Server failed to configure Remote Client connection (%s)", ProcessName, Name, Handle->Name, strerror(errno) ); return NULL; @@ -1269,7 +1252,7 @@ THandle * CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientA } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle ) { // Check state if (Handle->State == csOpen) { @@ -1278,7 +1261,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso } // Resolve IP Address - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create File descriptor @@ -1311,7 +1294,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle ) { // Socket options struct linger ServerLinger_opt; @@ -1330,7 +1313,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso } // Resolve Host & Port Names - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create socket @@ -1476,7 +1459,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) // Create Remote Client Handle sprintf( ClientName, "%s-%d", Handle->Name, ClientFD ); *RemoteClient = CreateHandle( ClientName, false ); - if (!SetSocketHandle( *RemoteClient, ctTCPremote, ClientAddress, ClientPort, 0, 0 )) { + if (!SetSocketHandle( *RemoteClient, ctTCPremote, ClientAddress, ClientPort, 0 )) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - TCP Server failed to configure Remote Client connection (%s)", ProcessName, Name, Handle->Name, strerror(errno) ); return NULL; @@ -1529,7 +1512,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle ) { // Socket options int KeepAlive_opt = 1; // Enable/disable keep alive @@ -1547,7 +1530,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso if (Handle->State != csWaitingtoOpen) { // Resolve IP Address - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create File descriptor @@ -1638,7 +1621,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } //--------------------------------------------------------------------------- -int CSelectableCore::Open( THandle * Handle, bool DelayResolve ) +int CSelectableCore::Open( THandle * Handle ) { THandle * NewHandle = NULL; @@ -1665,16 +1648,16 @@ int CSelectableCore::Open( THandle * Handle, bool DelayResolve ) NewHandle = OpenUNIXclientSocket( Handle ); break; case ctUDPserver : - NewHandle = OpenUDPserverSocket( Handle, DelayResolve ); + NewHandle = OpenUDPserverSocket( Handle ); break; case ctUDPclient : - NewHandle = OpenUDPclientSocket( Handle, DelayResolve ); + NewHandle = OpenUDPclientSocket( Handle ); break; case ctTCPserver : - NewHandle = OpenTCPserverSocket( Handle, DelayResolve ); + NewHandle = OpenTCPserverSocket( Handle ); break; case ctTCPclient : - NewHandle = OpenTCPclientSocket( Handle, DelayResolve ); + NewHandle = OpenTCPclientSocket( Handle ); break; default: NewHandle = NULL; @@ -1880,7 +1863,7 @@ bool CSelectableCore::Read( THandle * Handle ) if (Handle->Type == ctTCPremote) { OpenTCPremoteSocket( Handle ); } else if (Handle->Type == ctTCPclient) { - OpenTCPclientSocket( Handle, true ); + OpenTCPclientSocket( Handle ); } else if (Handle->Type == ctUNIXremote) { OpenUNIXremoteSocket( Handle ); } else if (Handle->Type == ctUNIXclient) { @@ -2042,7 +2025,7 @@ bool CSelectableCore::Write( THandle * Handle ) else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { // Attempt to re-open port - Open( Handle, true ); + Open( Handle ); } } @@ -2056,7 +2039,7 @@ bool CSelectableCore::Write( THandle * Handle ) if (Handle->Type == ctTCPremote) { OpenTCPremoteSocket( Handle ); } else if (Handle->Type == ctTCPclient) { - OpenTCPclientSocket( Handle, true ); + OpenTCPclientSocket( Handle ); } else if (Handle->Type == ctUNIXremote) { OpenUNIXremoteSocket( Handle ); } else if (Handle->Type == ctUNIXclient) { @@ -2207,11 +2190,11 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { // Complete opening process - Open( Handle, true ); + Open( Handle ); // Check if Handle is open - if (Handle->State == csOpenRequest) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle", + if (Handle->State == csPreparing) { + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Resolving (auto-managed) Handle", ProcessName, Name, Handle->Name ); return 0; } @@ -2353,16 +2336,14 @@ bool CSelectableCore::Process() while (Handle) { // Auto manage handles - if ((Handle->State == csOpenRequest)) { - // Resolve then open socket - if (Timeout( Handle->LastAction, Handle->ResolveDelay )) { - Open( Handle, false ); - } + if (Handle->State == csPrepared) { + // Proceed to open + Open( Handle ); } - else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) ) { + else if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) { // Try to re-open port after delay if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { - Open( Handle, false ); + Open( Handle ); } } diff --git a/SelectableCore.h b/SelectableCore.h index 98490a9..24d2d51 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -24,8 +24,8 @@ typedef enum { ctNone = 0, ctSerial = 1, ctLinePrinter = 2, ctForkPipe = 3, ctUN const char ConnectTypeName[][20] = { "None", "Serial Port", "Line Printer", "Fork Pipe", "UNIX Server", "UNIX Client", "UNIX Remote Client", "UDP Server", "UDP Client", "UDP Remote Client", "TCP Server", "TCP Client", "TCP Remote Client", "Custom" }; -typedef enum { csNone = 0, csOpenRequest = 1, csWaitingtoOpen = 2, csOpen = 3, csDataWaiting = 4, csClosed = 5, csFailed = 6 } EConnectState; -const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" }; +typedef enum { csNone = 0, csPreparing = 1, csPrepared = 2, csWaitingtoOpen = 3, csOpen = 4, csDataWaiting = 5, csClosed = 6, csFailed = 7 } EConnectState; +const char ConnectStateName[][15] = { "None", "Preparing", "Prepared", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" }; //--------------------------------------------------------------------------- @@ -91,7 +91,7 @@ struct SHandle { long CloseTimeout = 1000; // millisecs of no traffic before closing socket // Callback functions - FHandleCallback StateCallback[ 7 ] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + FHandleCallback StateCallback[ 8 ] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; // Type specific parameters char * Path = NULL; // Port (file)name or Exec path @@ -107,9 +107,7 @@ struct SHandle { bool AddressFailed = false; // Indicate failure to connect to address short Queue = 2; // Max waiting connections - long ResolveDelay = 0; // Delay before resolving hostname via DNS TResolveReq * ResolveReq = NULL; // DNS resolve request - bool Resolving = false; // Busy resolving address // Serial Port config bool SerialConfig = false; @@ -266,13 +264,13 @@ public: bool SetOutBuffer( THandle * Handle, int OutBufSize ); // FD Operations - virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0; + virtual int Open( THandle * Handle ) = 0; virtual bool Close( THandle * Handle, bool QuickReopen ); virtual bool Read( THandle * Handle ); virtual bool Write( THandle * Handle ); // FD operations - inline virtual int Open( const char * HandleName, bool DelayResolve = false ) { return (Open( GetHandle( HandleName ), DelayResolve)); }; + inline virtual int Open( const char * HandleName ) { return (Open( GetHandle( HandleName ))); }; inline virtual bool Close( const char * HandleName, bool QuickReopen ) { return (Close( GetHandle( HandleName ), QuickReopen )); }; inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); }; @@ -320,19 +318,19 @@ protected: THandle * OpenUNIXremoteSocket( THandle * Handle ); // Socket Operations - bool ResolveAddress( THandle * Handle, bool DelayResolve ); + bool ResolveAddress( THandle * Handle ); bool HandleResolve( THandle * Handle ); bool DestroyResolveReq( THandle * Handle, bool DestroyResult ); // Managing File Handles virtual bool DestroyHandle( THandle * Handle ); - THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve ); + THandle * OpenUDPserverSocket( THandle * Handle ); THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort ); - THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve ); - THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve ); + THandle * OpenUDPclientSocket( THandle * Handle ); + THandle * OpenTCPserverSocket( THandle * Handle ); THandle * OpenTCPremoteSocket( THandle * Handle ); - THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve ); + THandle * OpenTCPclientSocket( THandle * Handle ); // Mutual Operations int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen ); @@ -357,10 +355,10 @@ public: bool SetLinePrinterHandle( THandle * Handle, const char * FileName ); bool SetForkPipeHandle( THandle * Handle, const char * ExecPath ); bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue ); - bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay ); + bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue ); // FD Operations - virtual int Open( THandle * Handle, bool DelayResolve = false ); + virtual int Open( THandle * Handle ); virtual bool Close( THandle * Handle, bool QuickReopen ); virtual bool Read( THandle * Handle ); virtual bool Write( THandle * Handle ); From 253eb91824c3d7829b8c26032e1bcc0e129b886d Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 10 Jun 2019 17:25:31 +0200 Subject: [PATCH 12/24] Important Update: - FunctionCore: - Add OldState to ChannelStateEvent() - Add new method ChannelOutState() - Update Logging levels - SelectableCore: - Restart LastAction timer of Name Resolve fail (cause delayed re-open) - Watchdog: - Move JSON PingInterval param to "Config" object --- FunctionCore.cpp | 33 ++++++++++++++++++++++++++++----- FunctionCore.h | 3 ++- SelectableCore.cpp | 5 ++++- WatchdogCore.cpp | 2 +- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/FunctionCore.cpp b/FunctionCore.cpp index 6a3450f..3fc9596 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -202,6 +202,7 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelSt bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState State ) { + EChannelState OldState = Channel->State; TChannelLink * LinkChannel; // Validate @@ -210,13 +211,13 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState Sta // Update state Channel->State = State; - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Channel '%s' - State:%s", + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - State:%s", ProcessName, Name, Channel->Name, ChannelStateName[State] ); // Update linked channels LinkChannel = Channel->FirstLink; while (LinkChannel) { - LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, State ); + LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State ); LinkChannel = LinkChannel->Next; } @@ -224,7 +225,7 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState Sta } //--------------------------------------------------------------------------- -bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState State ) +bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { TChannelLink * LinkChannel; @@ -233,13 +234,35 @@ bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRe if (!(LinkChannel = GetLinkChannel( Channel, SourceRef ))) return false; - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Link Channel '%s'-->'%s' - State:%s", - ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ChannelStateName[State] ); + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - State:%s", + ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ChannelStateName[NewState] ); return true; } //--------------------------------------------------------------------------- +EChannelState CFunctionCore::ChannelOutState( TChannel * Channel, const char * TargetRef ) +{ + TChannelLink * LinkChannel = NULL; + EChannelState State = CH_off; + + // Validate + if (!Channel) + return State; + + // Check if any linked channels are ready + LinkChannel = Channel->FirstLink; + while (LinkChannel) { + if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) { + if (LinkChannel->Channel->State > State) + State = LinkChannel->Channel->State; + } + LinkChannel = LinkChannel->Next; + } + return State; +} +//--------------------------------------------------------------------------- + // Automated Data Input/Output bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output ) { diff --git a/FunctionCore.h b/FunctionCore.h index 72227e0..090bdd2 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -121,7 +121,8 @@ public: virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State ); virtual bool SetChannelState( TChannel * Channel, const EChannelState State ); - virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState State ); + virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ); + virtual EChannelState ChannelOutState( TChannel * Channel, const char * TargetRef ); // Pushing Data Output -> Input virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 ); diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 8561774..4703eaa 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -1060,6 +1060,7 @@ bool CSelectableCore::ResolveAddress( THandle * Handle ) DestroyResolveReq( Handle, true ); HandleState( Handle, csFailed ); + SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve return false; } return false; @@ -1101,6 +1102,7 @@ bool CSelectableCore::HandleResolve( THandle * Handle ) DestroyResolveReq( Handle, true ); HandleState( Handle, csFailed ); + SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve return false; } @@ -1120,6 +1122,7 @@ bool CSelectableCore::HandleResolve( THandle * Handle ) Handle->AddressInfo = NULL; HandleState( Handle, csFailed ); + SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve return false; } @@ -1807,7 +1810,7 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen ) }; // Change State - HandleState( Handle, ((Fail)? csFailed : csClosed) ); + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- diff --git a/WatchdogCore.cpp b/WatchdogCore.cpp index cebd535..c040958 100644 --- a/WatchdogCore.cpp +++ b/WatchdogCore.cpp @@ -63,7 +63,7 @@ bool CWatchdogCore::Init( CDataMember * FunctionConfig ) return false; // Set specific parameters - SetInterval( FunctionConfig->GetChInt( "Parameters/PingInterval", 500, true )); + SetInterval( Config->GetChInt( "PingInterval", 500, true )); // Create handle and set reference, if not done if (!(Ping = GetHandle( "Ping" ))) From 8791e25d2210cad75beb3f3dd468ec844469235a Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 16 Jun 2019 13:56:26 +0200 Subject: [PATCH 13/24] Important update: - DateTimeCore: - Added ReadDateTime() method, combining ReadDate() & ReadTime() - Added Read(Time/Date/DateTime)Str() methods for decoding date string --- DateTimeCore.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++++++- DateTimeCore.h | 7 ++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/DateTimeCore.cpp b/DateTimeCore.cpp index 628401e..7370793 100644 --- a/DateTimeCore.cpp +++ b/DateTimeCore.cpp @@ -204,6 +204,106 @@ bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, } //--------------------------------------------------------------------------- +bool ReadDateTime( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) +{ + struct tm CurrentTime; + + // Get current date and time + localtime_r( &EpochTime, &CurrentTime ); + + // Extract time + Hours = CurrentTime.tm_hour; + Minutes = CurrentTime.tm_min; + Seconds = CurrentTime.tm_sec; + + // Extract date + Day = CurrentTime.tm_mday; + Month = CurrentTime.tm_mon + 1; + Year = CurrentTime.tm_year + 1900; + + return true; +} +//--------------------------------------------------------------------------- + +// Read components from date/time string +bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ) +{ + int ItemsAssigned; + int TempDay; + int TempMonth; + int TempYear; + int TempHours = -1; + int TempMinutes = -1; + int TempSeconds = -1; + + // Read string + ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d", + &TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds ); + + // Return Values + Hours = (TempHours != -1)? TempHours : (Maxtime)? 23 : 0; + Minutes = (TempMinutes != -1)? TempMinutes : (Maxtime)? 59 : 0; + Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0; + + // Check if success + return ((ItemsAssigned == 6)? true : false); +} +//--------------------------------------------------------------------------- + +bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year ) +{ + int ItemsAssigned; + int TempDay; + int TempMonth; + int TempYear; + int TempHours = -1; + int TempMinutes = -1; + int TempSeconds = -1; + + // Read string + ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d", + &TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds ); + + // Return Values + Day = TempDay; + Month = TempMonth; + Year = TempYear; + + // Check if success + return ((ItemsAssigned == 6)? true : false); +} +//--------------------------------------------------------------------------- + +bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ) +{ + int ItemsAssigned; + int TempDay; + int TempMonth; + int TempYear; + int TempHours = -1; + int TempMinutes = -1; + int TempSeconds = -1; + + // Read string + ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d", + &TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds ); + + // Return Values + Day = TempDay; + Month = TempMonth; + Year = TempYear; + + Hours = (TempHours != -1)? TempHours : (Maxtime)? 23 : 0; + Minutes = (TempMinutes != -1)? TempMinutes : (Maxtime)? 59 : 0; + Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0; + + // Check if success + return ((ItemsAssigned == 6)? true : false); +} +//--------------------------------------------------------------------------- + // Get the current date in a string char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator ) { @@ -250,8 +350,7 @@ char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparato unsigned char Seconds; // Get Date & Time - ReadDate( EpochTime, Day, Month, Year ); - ReadTime( EpochTime, Hours, Minutes, Seconds ); + ReadDateTime( EpochTime, Day, Month, Year, Hours, Minutes, Seconds ); // Build String sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", diff --git a/DateTimeCore.h b/DateTimeCore.h index dea4957..7b3c198 100644 --- a/DateTimeCore.h +++ b/DateTimeCore.h @@ -31,6 +31,13 @@ char const * GetDateTimeStr( const char * DateSeparator = "/", const char * Tim bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year ); +bool ReadDateTime( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); + +bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ); +bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year ); +bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ); char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator = "/" ); char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator = ":" ); From 794b7e54860fd0a49108169c16babfcd05a63e6f Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 17 Jun 2019 12:43:12 +0200 Subject: [PATCH 14/24] Important Update: - FunctionCore: - Implement UnlinkChannel() - Avoid memory errors on application shutdown (state events) - Unlink channels before destroying in Function destructor - Bug fix: Linked Channels not added correctly --- FunctionCore.cpp | 69 +++++++++++++++++++++++++++++++++++++++--------- FunctionCore.h | 1 + 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/FunctionCore.cpp b/FunctionCore.cpp index 3fc9596..c7cc299 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -48,18 +48,15 @@ CFunctionCore::~CFunctionCore() // Destroy Channels while (FirstChannel) { - // Destroy Parameters - if (FirstChannel->Name) { - free( FirstChannel->Name ); - free( FirstChannel->Ref ); - } - // Destroy Linked Channels - while (FirstChannel->FirstLink) { - NextLinkedChannel = FirstChannel->FirstLink->Next; - delete FirstChannel->FirstLink; - FirstChannel->FirstLink = NextLinkedChannel; - } + while (FirstChannel->FirstLink) + UnlinkChannel( FirstChannel->Name, FirstChannel->FirstLink->Function->Name, FirstChannel->FirstLink->Channel->Name ); + + // Destroy Parameters + if (FirstChannel->Name) + free( FirstChannel->Name ); + if (FirstChannel->Ref) + free( FirstChannel->Ref ); // Destroy Channel NextChannel = FirstChannel->Next; @@ -280,7 +277,7 @@ bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunc // Check if linked Channel exists LinkedChannel = &(Channel->FirstLink); - while (*LinkedChannel && ((*LinkedChannel)->Channel == LinkChannel)) + while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel)) LinkedChannel = &((*LinkedChannel)->Next); if (!*LinkedChannel) *LinkedChannel = new TChannelLink; @@ -297,7 +294,7 @@ bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunc // Find Linked channel on remote function LinkedChannel = &(LinkChannel->FirstLink); - while (*LinkedChannel && ((*LinkedChannel)->Channel == Channel)) + while (*LinkedChannel && ((*LinkedChannel)->Channel != Channel)) LinkedChannel = &((*LinkedChannel)->Next); if (!*LinkedChannel) *LinkedChannel = new TChannelLink; @@ -315,6 +312,52 @@ bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunc } //--------------------------------------------------------------------------- +bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName ) +{ + TChannel * Channel = NULL; + CFunctionCore * LinkFunction = NULL; + TChannel * LinkChannel = NULL; + TChannelLink ** LinkedChannel = NULL; + TChannelLink * NextLinkedChannel = NULL; + + // Check if Channels & Function exist + if (!(Channel = GetChannel( ChannelName )) || + !(LinkFunction = Application->GetFunction( LinkFunctionName )) || + !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) { + return false; + } + + // Check if linked Channel exists + LinkedChannel = &(Channel->FirstLink); + while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel)) + LinkedChannel = &((*LinkedChannel)->Next); + + // Unlink channel + if (*LinkedChannel) { + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Unlinked - '%s'-x->'%s'", + ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref ); + NextLinkedChannel = (*LinkedChannel)->Next; + delete *LinkedChannel; + *LinkedChannel = NextLinkedChannel; + } + + // Find Linked channel on remote function + LinkedChannel = &(LinkChannel->FirstLink); + while (*LinkedChannel && ((*LinkedChannel)->Channel != Channel)) + LinkedChannel = &((*LinkedChannel)->Next); + + // Unlink channel + if (*LinkedChannel) { + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Unlinked - '%s'-x->'%s'", + ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref ); + NextLinkedChannel = (*LinkedChannel)->Next; + delete *LinkedChannel; + *LinkedChannel = NextLinkedChannel; + } + return true; +} +//--------------------------------------------------------------------------- + int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len ) { TChannel * Channel = NULL; diff --git a/FunctionCore.h b/FunctionCore.h index 090bdd2..6f77962 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -130,6 +130,7 @@ public: // Automated Data Input/Output virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output ); + virtual bool UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName ); virtual bool Process() = 0; friend class CApplication; From 207caa696d199529d1d8e415f6bbc8c6f086b550 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Wed, 19 Jun 2019 11:18:34 +0200 Subject: [PATCH 15/24] Important Update: - DateTimeCore: - Added new functions Get/SetDateTime() for combined date & time get/set - Added LocalTime param to ReadDate/Time() and BuildDate/TimeStr() - Allow input time to interpretted as ether UTC or local time - DeviceCore: - Added SourceRef to HandleCommand() --- DateTimeCore.cpp | 159 +++++++++++++++++++++++++++++++++-------------- DateTimeCore.h | 23 ++++--- DeviceCore.cpp | 2 +- DeviceCore.h | 2 +- FunctionCore.cpp | 1 - 5 files changed, 129 insertions(+), 58 deletions(-) diff --git a/DateTimeCore.cpp b/DateTimeCore.cpp index 7370793..8340054 100644 --- a/DateTimeCore.cpp +++ b/DateTimeCore.cpp @@ -20,24 +20,24 @@ static char ReturnStr[30]; //--------------------------------------------------------------------------- -// Set current time on real-time clock bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds ) { struct tm NewTime; struct timeval tv; struct timezone tz; - // Get current date and time + // Get current Epoch (UTC) gettimeofday( &tv, &tz); - // Change to new time + // Convert to local time localtime_r( &tv.tv_sec, &NewTime ); + // Set new time (keep date as is) NewTime.tm_hour = Hours; NewTime.tm_min = Minutes; NewTime.tm_sec = Seconds; - // Convert back + // Convert back from local time to epoch time tv.tv_sec = mktime( &NewTime ); tv.tv_usec = 0; @@ -47,43 +47,24 @@ bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds } //--------------------------------------------------------------------------- -// Get current time from real-time clock -bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) -{ - struct tm CurrentTime; - time_t UTC; - - // Get current date and time - time( &UTC ); - localtime_r( &UTC, &CurrentTime ); - - // Extract time - Hours = CurrentTime.tm_hour; - Minutes = CurrentTime.tm_min; - Seconds = CurrentTime.tm_sec; - - return true; -} -//--------------------------------------------------------------------------- - -// Set current date on real-time clock bool SetDate( unsigned char Day, unsigned char Month, unsigned Year ) { struct tm NewDate; struct timeval tv; struct timezone tz; - // Get current date and time + // Get current Epoch (UTC) gettimeofday( &tv, &tz ); - // Change to new time + // Convert to local time localtime_r( &tv.tv_sec, &NewDate ); + // Set new date (keep time as is) NewDate.tm_year = Year - 1900; NewDate.tm_mon = Month - 1; NewDate.tm_mday = Day; - // Convert back + // Convert back from local time to epoch time tv.tv_sec = mktime( &NewDate ); tv.tv_usec = 0; @@ -94,17 +75,70 @@ bool SetDate( unsigned char Day, unsigned char Month, unsigned Year ) } //--------------------------------------------------------------------------- -// Get current data from real-time clock +bool SetDateTime( unsigned char Day, unsigned char Month, unsigned Year, + unsigned char Hours, unsigned char Minutes, unsigned char Seconds ) +{ + struct tm NewTime; + struct timeval tv; + struct timezone tz; + + // Get current Epoch (UTC) + gettimeofday( &tv, &tz); + + // Convert to local time + localtime_r( &tv.tv_sec, &NewTime ); + + // Set new date & time + NewTime.tm_year = Year - 1900; + NewTime.tm_mon = Month - 1; + NewTime.tm_mday = Day; + + NewTime.tm_hour = Hours; + NewTime.tm_min = Minutes; + NewTime.tm_sec = Seconds; + + // Convert back from local time to epoch time + tv.tv_sec = mktime( &NewTime ); + tv.tv_usec = 0; + + // Set date and new time + settimeofday( &tv, &tz); + return true; +} +//--------------------------------------------------------------------------- + +bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) +{ + struct tm CurrentTime; + time_t UTC; + + // Get current UTC date and time + time( &UTC ); + + // Convert to local time + localtime_r( &UTC, &CurrentTime ); + + // Extract time only + Hours = CurrentTime.tm_hour; + Minutes = CurrentTime.tm_min; + Seconds = CurrentTime.tm_sec; + + return true; +} +//--------------------------------------------------------------------------- + bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year ) { struct tm CurrentDate; time_t UTC; - // Get current date and time + // Get current UTC date and time time( &UTC ); + + // Convert to local time localtime_r( &UTC, &CurrentDate ); - // Extract date + // Extract date only Day = CurrentDate.tm_mday; Month = CurrentDate.tm_mon + 1; Year = CurrentDate.tm_year + 1900; @@ -113,7 +147,31 @@ bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year ) } //--------------------------------------------------------------------------- -// Get the current date in a string +bool GetDateTime( unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) +{ + struct tm CurrentTime; + time_t UTC; + + // Get current UTC date and time + time( &UTC ); + + // Convert to local time + localtime_r( &UTC, &CurrentTime ); + + // Extract Date & time + Day = CurrentTime.tm_mday; + Month = CurrentTime.tm_mon + 1; + Year = CurrentTime.tm_year + 1900; + + Hours = CurrentTime.tm_hour; + Minutes = CurrentTime.tm_min; + Seconds = CurrentTime.tm_sec; + + return true; +} +//--------------------------------------------------------------------------- + char const * GetDateStr( const char * DateSeparator ) { unsigned char Day; @@ -172,12 +230,15 @@ char const * GetDateTimeStr( const char * DateSeparator, const char * TimeSepar //--------------------------------------------------------------------------- // Get current time from real-time clock -bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) +bool ReadTime( const time_t EpochTime, bool LocalTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) { struct tm CurrentTime; // Get current date and time - localtime_r( &EpochTime, &CurrentTime ); + if (LocalTime) + localtime_r( &EpochTime, &CurrentTime ); + else + gmtime_r( &EpochTime, &CurrentTime ); // Extract time Hours = CurrentTime.tm_hour; @@ -188,12 +249,15 @@ bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minu } //--------------------------------------------------------------------------- -bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year ) +bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year ) { struct tm CurrentDate; // Get current date and time - localtime_r( &EpochTime, &CurrentDate ); + if (LocalTime) + localtime_r( &EpochTime, &CurrentDate ); + else + gmtime_r( &EpochTime, &CurrentDate ); // Extract date Day = CurrentDate.tm_mday; @@ -204,13 +268,16 @@ bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, } //--------------------------------------------------------------------------- -bool ReadDateTime( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year, +bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ) { struct tm CurrentTime; // Get current date and time - localtime_r( &EpochTime, &CurrentTime ); + if (LocalTime) + localtime_r( &EpochTime, &CurrentTime ); + else + gmtime_r( &EpochTime, &CurrentTime ); // Extract time Hours = CurrentTime.tm_hour; @@ -247,7 +314,7 @@ bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0; // Check if success - return ((ItemsAssigned == 6)? true : false); + return ((ItemsAssigned >= 3)? true : false); } //--------------------------------------------------------------------------- @@ -271,7 +338,7 @@ bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &M Year = TempYear; // Check if success - return ((ItemsAssigned == 6)? true : false); + return ((ItemsAssigned >= 3)? true : false); } //--------------------------------------------------------------------------- @@ -300,19 +367,19 @@ bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned cha Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0; // Check if success - return ((ItemsAssigned == 6)? true : false); + return ((ItemsAssigned >= 3)? true : false); } //--------------------------------------------------------------------------- // Get the current date in a string -char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator ) +char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator ) { unsigned char Day; unsigned char Month; unsigned int Year; // Get Date - ReadDate( EpochTime, Day, Month, Year ); + ReadDate( EpochTime, LocalTime, Day, Month, Year ); // Build String sprintf( ReturnStr, "%04d%s%02d%s%02d", @@ -323,14 +390,14 @@ char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator ) } //--------------------------------------------------------------------------- -char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator ) +char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator ) { unsigned char Hours; unsigned char Minutes; unsigned char Seconds; // Get Date & Time - ReadTime( EpochTime, Hours, Minutes, Seconds ); + ReadTime( EpochTime, LocalTime, Hours, Minutes, Seconds ); // Build String sprintf( ReturnStr, "%02d%s%02d%s%02d", @@ -340,7 +407,7 @@ char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator ) } //--------------------------------------------------------------------------- -char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator, const char * TimeSeparator ) +char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator, const char * TimeSeparator ) { unsigned char Day; unsigned char Month; @@ -350,7 +417,7 @@ char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparato unsigned char Seconds; // Get Date & Time - ReadDateTime( EpochTime, Day, Month, Year, Hours, Minutes, Seconds ); + ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds ); // Build String sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", diff --git a/DateTimeCore.h b/DateTimeCore.h index 7b3c198..e3992c3 100644 --- a/DateTimeCore.h +++ b/DateTimeCore.h @@ -17,11 +17,15 @@ //--------------------------------------------------------------------------- // Get and set System Date and Time -bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds ); bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); - -bool SetDate( unsigned char Day, unsigned char Month, unsigned Year ); bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year ); +bool GetDateTime( unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); + +bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds ); +bool SetDate( unsigned char Day, unsigned char Month, unsigned Year ); +bool SetDateTime( unsigned char Day, unsigned char Month, unsigned Year, + unsigned char Hours, unsigned char Minutes, unsigned char Seconds ); char const * GetDateStr( const char * DateSeparator = "/" ); char const * GetTimeStr( const char * TimeSeparator = ":" ); @@ -29,9 +33,10 @@ char const * GetDateTimeStr( const char * DateSeparator = "/", const char * Tim //--------------------------------------------------------------------------- -bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); -bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year ); -bool ReadDateTime( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year, +// Build or interpret time data +bool ReadTime( const time_t EpochTime, bool LocalTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); +bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year ); +bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ); @@ -39,9 +44,9 @@ bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ); -char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator = "/" ); -char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator = ":" ); -char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" ); +char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/" ); +char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator = ":" ); +char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" ); //--------------------------------------------------------------------------- diff --git a/DeviceCore.cpp b/DeviceCore.cpp index d648dae..125c6cb 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -1534,7 +1534,7 @@ bool CDeviceCore::GetCmdParam( const char * Start, char * Param, char ** NextPar } //--------------------------------------------------------------------------- -int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, const int MaxLen ) +int CDeviceCore::HandleCommand( const char *ChannelName, const char * SourceRef, const char * Data, const int MaxLen ) { int Len; char Value[50]; diff --git a/DeviceCore.h b/DeviceCore.h index 7d601d5..a982257 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -387,7 +387,7 @@ public: // Handle Interface Commands bool GetCmdParam( const char * Start, char * Param, char ** NextParam ); - int HandleCommand( const char *ChannelName, const char * Data, const int MaxLen ); + int HandleCommand( const char *ChannelName, const char * SourceRef, const char * Data, const int MaxLen ); // Command Text Interfaces bool SetValue( TDeviceParam * Param, const char * Value, const int Len, bool Force ); diff --git a/FunctionCore.cpp b/FunctionCore.cpp index c7cc299..f56f82f 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -43,7 +43,6 @@ CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( p CFunctionCore::~CFunctionCore() { TChannel * NextChannel = NULL; - TChannelLink * NextLinkedChannel = NULL; // Destroy Channels while (FirstChannel) From e9b50f1af9219d436fe66ad18883f4fbf50b0760 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 23 Jun 2019 10:38:27 +0200 Subject: [PATCH 16/24] Important Update: - FunctionCore/SelectableCore: - Replace Channel->State with InState - Add Channel-OutState (ready for output) updated by ChannelStateEvent() - TimingCore: - Add GetUpCounter() for calculating uptime string (in seconds) --- FunctionCore.cpp | 66 +++++++++++++++++++++++++++++----------------- FunctionCore.h | 3 ++- SelectableBare.cpp | 4 +-- TimingCore.h | 35 +++++++++++++++++++++++- 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/FunctionCore.cpp b/FunctionCore.cpp index f56f82f..1b0de8a 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -186,11 +186,13 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelSt (*Channel)->Name = strdup( ChannelName ); (*Channel)->Ref = (char*)malloc( strlen(Name)+strlen(ChannelName)+2 ); sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName ); - (*Channel)->State = State; + (*Channel)->InState = State; + (*Channel)->OutState = CH_off; // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', State:%s", - ProcessName, Name, ChannelName, (*Channel)->Ref, ChannelStateName[(*Channel)->State] ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', In:%s, Out:%s", + ProcessName, Name, ChannelName, (*Channel)->Ref, + ChannelStateName[(*Channel)->InState], ChannelStateName[(*Channel)->OutState]); } return *Channel; } @@ -198,7 +200,7 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelSt bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState State ) { - EChannelState OldState = Channel->State; + EChannelState OldState = Channel->InState; TChannelLink * LinkChannel; // Validate @@ -206,8 +208,8 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState Sta return false; // Update state - Channel->State = State; - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - State:%s", + Channel->InState = State; + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s", ProcessName, Name, Channel->Name, ChannelStateName[State] ); // Update linked channels @@ -223,16 +225,34 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState Sta bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { + TChannelLink * UpdateChannel; TChannelLink * LinkChannel; + EChannelState OutState; + // Validate if (!Channel) return false; - if (!(LinkChannel = GetLinkChannel( Channel, SourceRef ))) + if (!(UpdateChannel = GetLinkChannel( Channel, SourceRef ))) return false; - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - State:%s", - ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ChannelStateName[NewState] ); + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s", + ProcessName, Name, Channel->Name, UpdateChannel->Channel->Ref, ChannelStateName[NewState] ); + // Check if channel Out state changed + OutState = CH_off; + LinkChannel = Channel->FirstLink; + while (LinkChannel) { + if (LinkChannel->Channel->InState > OutState) + OutState = LinkChannel->Channel->InState; + LinkChannel = LinkChannel->Next; + } + if (OutState != Channel->OutState) { + // Update output state + Channel->OutState = OutState; + + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - Out:%s", + ProcessName, Name, Channel->Name, ChannelStateName[OutState] ); + } return true; } //--------------------------------------------------------------------------- @@ -240,22 +260,20 @@ bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRe EChannelState CFunctionCore::ChannelOutState( TChannel * Channel, const char * TargetRef ) { TChannelLink * LinkChannel = NULL; - EChannelState State = CH_off; // Validate - if (!Channel) - return State; - - // Check if any linked channels are ready - LinkChannel = Channel->FirstLink; - while (LinkChannel) { - if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) { - if (LinkChannel->Channel->State > State) - State = LinkChannel->Channel->State; - } - LinkChannel = LinkChannel->Next; + if (!Channel) { + return CH_off; + } + else if (!TargetRef || !*TargetRef) { + return Channel->OutState; + } + else if ((LinkChannel = GetLinkChannel( Channel, TargetRef ))) { + return LinkChannel->Channel->InState; + } + else { + return CH_off; } - return State; } //--------------------------------------------------------------------------- @@ -373,9 +391,9 @@ int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, cons ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->State) { + else if (!Channel->InState) { if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s", - ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->State] ); + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->InState] ); return 0; } diff --git a/FunctionCore.h b/FunctionCore.h index 6f77962..807414b 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -38,7 +38,8 @@ struct SChannel TChannelLink * FirstLink = NULL; // List of channels linked for input/output - EChannelState State = CH_off; // Channel ready to receive input + EChannelState InState = CH_off; // Channel ready to receive input (determined by parent function) + EChannelState OutState = CH_off; // Channel ready to send output (determined by InStates of linked channels) TChannel * Next = NULL; }; diff --git a/SelectableBare.cpp b/SelectableBare.cpp index 265e691..b0f2134 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -190,7 +190,7 @@ bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) ChannelState = CH_ready; else ChannelState = CH_off; - if (Handle->Channel->State != ChannelState) + if (Handle->Channel->InState != ChannelState) SetChannelState( Handle->Channel, ChannelState ); } return true; @@ -677,7 +677,7 @@ int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, co ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (Channel->State != CH_ready) { + else if (Channel->InState != CH_ready) { // Channel disabled if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); diff --git a/TimingCore.h b/TimingCore.h index 8718f6e..ce97f65 100644 --- a/TimingCore.h +++ b/TimingCore.h @@ -12,6 +12,7 @@ #include #include #include +#include // redA Libraries /* none */ @@ -23,19 +24,22 @@ inline void SetInterval( timeval * Time, long MilliSeconds ) { Time->tv_sec = MilliSeconds / 1000; Time->tv_usec = (MilliSeconds % 1000) * 1000; }; +//--------------------------------------------------------------------------- // Mark start time inline void SetStartTime( timeval *StartTime ) { gettimeofday( StartTime, NULL ); }; +//--------------------------------------------------------------------------- // Clear timer inline void ClearStartTime( timeval * StartTime ) { StartTime->tv_sec = 0; StartTime->tv_usec = 0; }; +//--------------------------------------------------------------------------- -// Time passed since start time +// Milli-seconds passed since start time inline long TimePassed( timeval StartTime ) { timeval CurrTime; long Duration; @@ -47,17 +51,46 @@ inline long TimePassed( timeval StartTime ) { Duration = LONG_MAX; return Duration; }; +//--------------------------------------------------------------------------- // Time remaining from Start time to given time out inline long TimeLeft( timeval StartTime, long MilliSeconds ) { return (MilliSeconds - TimePassed(StartTime)); }; +//--------------------------------------------------------------------------- // Has give time expired after start time inline bool Timeout( timeval StartTime, long MilliSeconds ) { return ((TimePassed(StartTime) > MilliSeconds)? true : false); }; +//--------------------------------------------------------------------------- +// Get Upcount in seconds from start time (with string output) +inline long GetUpCounter( timeval StartTime, char * TextStr ) { + long Duration; + int Days, Hours, Minutes, Seconds; + timeval CurrTime; + + // Get duration + gettimeofday( &CurrTime, NULL ); + Duration = (!StartTime.tv_sec)? 0 : (CurrTime.tv_sec - StartTime.tv_sec); // Handle zero start + + // Create string + if (TextStr) { + // Get Parts + Minutes = Duration / 60; + Hours = Minutes / 60; + Days = Hours / 24; + + // Get modulus + Seconds = Duration % 60; + Minutes = Minutes % 60; + Hours = Hours % 24; + + sprintf( TextStr, "%dd %02d:%02d:%02d", Days, Hours, Minutes, Seconds ); + } + return Duration; +} //--------------------------------------------------------------------------- #endif /* REDACORE_TIMINGCORE_H_ */ From 9f8f69de3f84970c5c52fd687b55c334ac0d2adc Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 23 Jun 2019 18:03:37 +0200 Subject: [PATCH 17/24] Important Update: - FunctionCore: - Improve Channel Events: - Remove important actions from ChannelStateEvent() (now only used for custom actions) - Add new method UpdateChannelOutState() - Add Channel Events to Link and Unlink actions - Rename SetChannelState() -> SetChannelInState() - Use Channel->Ref (instead of name) on all channel events - DeviceCore/SelectableCore: - Rename SetChannelState() -> SetChannelInState() --- DeviceCore.cpp | 6 +++--- FunctionCore.cpp | 38 +++++++++++++++++++++++--------------- FunctionCore.h | 7 ++++--- SelectableBare.cpp | 2 +- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 125c6cb..fcfb818 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -70,17 +70,17 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) if (!(CmdChannel = GetChannel( "Command" ))) CmdChannel = AddChannel( "Command", CH_ready ); else - SetChannelState( CmdChannel, CH_ready ); + SetChannelInState( CmdChannel, CH_ready ); if (!(DeviceChannel = GetChannel( "Device" ))) DeviceChannel = AddChannel( "Device", CH_ready ); else - SetChannelState( DeviceChannel, CH_ready ); + SetChannelInState( DeviceChannel, CH_ready ); if (!(EventChannel = GetChannel( "Event" ))) EventChannel = AddChannel( "Event", CH_ready ); else - SetChannelState( EventChannel, CH_ready ); + SetChannelInState( EventChannel, CH_ready ); // Load Polling configuration PollConfig = Config->GetChild( "Polling", true ); diff --git a/FunctionCore.cpp b/FunctionCore.cpp index 1b0de8a..6b9eac6 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -198,7 +198,7 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelSt } //--------------------------------------------------------------------------- -bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState State ) +bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State ) { EChannelState OldState = Channel->InState; TChannelLink * LinkChannel; @@ -210,12 +210,18 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState Sta // Update state Channel->InState = State; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s", - ProcessName, Name, Channel->Name, ChannelStateName[State] ); + ProcessName, Name, Channel->Ref, ChannelStateName[State] ); // Update linked channels LinkChannel = Channel->FirstLink; while (LinkChannel) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s", + ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] ); + + // Trigger Linked Channel Events LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State ); + LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel ); + LinkChannel = LinkChannel->Next; } @@ -223,21 +229,11 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState Sta } //--------------------------------------------------------------------------- -bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) +bool CFunctionCore::UpdateChannelOutState( TChannel * Channel ) { - TChannelLink * UpdateChannel; TChannelLink * LinkChannel; EChannelState OutState; - // Validate - if (!Channel) - return false; - if (!(UpdateChannel = GetLinkChannel( Channel, SourceRef ))) - return false; - - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s", - ProcessName, Name, Channel->Name, UpdateChannel->Channel->Ref, ChannelStateName[NewState] ); - // Check if channel Out state changed OutState = CH_off; LinkChannel = Channel->FirstLink; @@ -251,13 +247,13 @@ bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRe Channel->OutState = OutState; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - Out:%s", - ProcessName, Name, Channel->Name, ChannelStateName[OutState] ); + ProcessName, Name, Channel->Ref, ChannelStateName[OutState] ); } return true; } //--------------------------------------------------------------------------- -EChannelState CFunctionCore::ChannelOutState( TChannel * Channel, const char * TargetRef ) +EChannelState CFunctionCore::GetChannelOutState( TChannel * Channel, const char * TargetRef ) { TChannelLink * LinkChannel = NULL; @@ -325,6 +321,14 @@ bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunc // Log Event if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Linked - '%s'-->'%s' - In:%s, Out:%s", ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref, ((Output)? "Yes" : "No"), ((Input)? "Yes" : "No") ); + + // Trigger Forward Channel Events + LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState ); + LinkFunction->UpdateChannelOutState( LinkChannel ); + + // Trigger Reverse Channel Events + ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState ); + UpdateChannelOutState( Channel ); return true; } //--------------------------------------------------------------------------- @@ -371,6 +375,10 @@ bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFu delete *LinkedChannel; *LinkedChannel = NextLinkedChannel; } + + // Trigger Channel Events + LinkFunction->UpdateChannelOutState( LinkChannel ); + UpdateChannelOutState( Channel ); return true; } //--------------------------------------------------------------------------- diff --git a/FunctionCore.h b/FunctionCore.h index 807414b..f17bfec 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -121,9 +121,10 @@ public: // Manage Channels virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State ); - virtual bool SetChannelState( TChannel * Channel, const EChannelState State ); - virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ); - virtual EChannelState ChannelOutState( TChannel * Channel, const char * TargetRef ); + virtual bool SetChannelInState( TChannel * Channel, const EChannelState State ); + virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { return true; }; + virtual bool UpdateChannelOutState( TChannel * Channel ); + virtual EChannelState GetChannelOutState( TChannel * Channel, const char * TargetRef ); // Pushing Data Output -> Input virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 ); diff --git a/SelectableBare.cpp b/SelectableBare.cpp index b0f2134..cddcfac 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -191,7 +191,7 @@ bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) else ChannelState = CH_off; if (Handle->Channel->InState != ChannelState) - SetChannelState( Handle->Channel, ChannelState ); + SetChannelInState( Handle->Channel, ChannelState ); } return true; } From 14af8390ec5e1ff8a84413b1e1c1e78d9b3a3f87 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 23 Jun 2019 20:51:51 +0200 Subject: [PATCH 18/24] Important Update: - FunctionCore: - Bug Fix: Change Channel OutState before triggering event - TimingCore: - Add method SecondsPassed() (provides seconds instead of milli-seconds) --- FunctionCore.cpp | 6 +++--- TimingCore.h | 14 +++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/FunctionCore.cpp b/FunctionCore.cpp index 6b9eac6..d60ab65 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -219,8 +219,8 @@ bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState S ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] ); // Trigger Linked Channel Events - LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State ); LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel ); + LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State ); LinkChannel = LinkChannel->Next; } @@ -323,12 +323,12 @@ bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunc ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref, ((Output)? "Yes" : "No"), ((Input)? "Yes" : "No") ); // Trigger Forward Channel Events - LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState ); LinkFunction->UpdateChannelOutState( LinkChannel ); + LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState ); // Trigger Reverse Channel Events - ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState ); UpdateChannelOutState( Channel ); + ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState ); return true; } //--------------------------------------------------------------------------- diff --git a/TimingCore.h b/TimingCore.h index ce97f65..14f8ece 100644 --- a/TimingCore.h +++ b/TimingCore.h @@ -53,6 +53,16 @@ inline long TimePassed( timeval StartTime ) { }; //--------------------------------------------------------------------------- +inline long SecondsPassed( timeval StartTime ) { + timeval CurrTime; + long Duration; + + gettimeofday( &CurrTime, NULL ); + Duration = CurrTime.tv_sec - StartTime.tv_sec; + return Duration; +}; +//--------------------------------------------------------------------------- + // Time remaining from Start time to given time out inline long TimeLeft( timeval StartTime, long MilliSeconds ) { return (MilliSeconds - TimePassed(StartTime)); @@ -69,11 +79,9 @@ inline bool Timeout( timeval StartTime, long MilliSeconds ) { inline long GetUpCounter( timeval StartTime, char * TextStr ) { long Duration; int Days, Hours, Minutes, Seconds; - timeval CurrTime; // Get duration - gettimeofday( &CurrTime, NULL ); - Duration = (!StartTime.tv_sec)? 0 : (CurrTime.tv_sec - StartTime.tv_sec); // Handle zero start + Duration = SecondsPassed( StartTime ); // Create string if (TextStr) { From 7d69edffa2ea4a1741291b71da9589fda9d4df73 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Wed, 10 Jul 2019 19:37:01 +0200 Subject: [PATCH 19/24] Important Update: - DeviceCore: - Added Data Type "bool" - Create boolean var for params of type "bool" --- DeviceCore.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++---- DeviceCore.h | 18 +++++----- 2 files changed, 99 insertions(+), 14 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 5beb5f9..7616beb 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -243,15 +243,16 @@ bool CDeviceCore::CopyTemplateParam( TDevice * Device, TDeviceParam * Template, SetDataPath( Param, DataPath, DataNode ); } - if ((Template->DataType == dtUnsigned16) || (Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) { - UpdateUnsignedValue( Param, *((u_int16_t*)Template->Value), Template->Changed ); + if ((Template->DataType == dtBool) || (Template->DataType == dtUnsigned16) || + (Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) { + UpdateUnsignedValue( Param, *((u_int32_t*)Template->Value), Template->Changed ); if (Template->SetChanged) - SetUnsignedValue( Param, *((u_int16_t*)Template->Value), true ); + SetUnsignedValue( Param, *((u_int32_t*)Template->Value), true ); } else if ((Template->DataType == dtSigned16) || (Template->DataType == dtSigned32_HL) || (Template->DataType == dtSigned32_LH)) { - UpdateSignedValue( Param, *((int16_t*)Template->Value), Template->Changed ); + UpdateSignedValue( Param, *((int32_t*)Template->Value), Template->Changed ); if (Template->SetChanged) - SetSignedValue( Param, *((int16_t*)Template->Value), true ); + SetSignedValue( Param, *((int32_t*)Template->Value), true ); } else if ((Template->DataType == dtFloat32_L) || (Template->DataType == dtFloat32_B)) { UpdateFloatValue( Param, *((float*)Template->Value), Template->Changed ); @@ -389,7 +390,8 @@ bool CDeviceCore::InitDeviceParam( TDevice * Device, CDataMember * ParamConfig, SetDataPath( Param, DataPath, DataNode ); if ((InitVal = ParamConfig->GetChild( "InitValue", false ))) { - if ((DataType == dtUnsigned16) || (DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) { + if ((DataType == dtBool) || (DataType == dtUnsigned16) || + (DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) { UpdateUnsignedValue( Param, InitVal->GetInt(0), Read ); if (Write) SetUnsignedValue( Param, InitVal->GetInt(0), true ); @@ -681,6 +683,18 @@ TDeviceParam * CDeviceCore::AddDeviceParam( TDevice * Device, const char * Param // Init values switch (DataType) { + case dtBool : + // Create Value pointer + (*Param)->Value = (bool*)malloc( sizeof(bool) ); + *((bool*)(*Param)->Value) = 0; + (*Param)->Len = sizeof(bool); + + // Create Set Value pointer + (*Param)->SetValue = (bool*)malloc( sizeof(bool) ); + *((bool*)(*Param)->SetValue) = 0; + (*Param)->SetLen = sizeof(bool); + break; + case dtUnsigned16 : // Create Value pointer (*Param)->Value = (u_int16_t*)malloc( sizeof(u_int16_t) ); @@ -971,6 +985,25 @@ bool CDeviceCore::UpdateUnsignedValue( TDeviceParam * Param, const u_int32_t Val switch (Param->DataType) { + case dtBool : + if (Init || (*((bool*)Param->Value) != Value)) + { + // Set new value & mark change + *((bool*)Param->Value) = Value; + + if (Param->DataNode) + Param->DataNode->SetInt( *((bool*)Param->Value) ); + + // Mark change & log event + Changed = true; + if (Log) { + char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; + Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %u", ProcessName, Name, + ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) ); + } + } + break; + case dtUnsigned16 : if (Init || (*((u_int16_t*)Param->Value) != Value)) { @@ -1054,6 +1087,25 @@ bool CDeviceCore::UpdateSignedValue( TDeviceParam * Param, const int32_t Value, switch (Param->DataType) { + case dtBool : + if (Init || (*((bool*)Param->Value) != Value)) + { + // Set new value & mark change + *((bool*)Param->Value) = Value; + + if (Param->DataNode) + Param->DataNode->SetInt( *((bool*)Param->Value) ); + + // Mark change & log event + Changed = true; + if (Log) { + char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; + Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %d", ProcessName, Name, + ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) ); + } + } + break; + case dtSigned16 : if (Init || (*((int16_t*)Param->Value) != Value)) { @@ -1209,6 +1261,17 @@ bool CDeviceCore::SetUnsignedValue( TDeviceParam * Param, const u_int32_t Value, switch (Param->DataType) { + case dtBool : + if (Force || (*((bool*)Param->SetValue) != Value)) + { + // Set new value + *((bool*)Param->SetValue) = Value; + + // Mark change + Param->SetChanged = true; + } + break; + case dtUnsigned16 : if (Force || (*((u_int16_t*)Param->SetValue) != Value)) { @@ -1249,6 +1312,17 @@ bool CDeviceCore::SetSignedValue( TDeviceParam * Param, const int32_t Value, boo switch (Param->DataType) { + case dtBool : + if (Force || (*((bool*)Param->SetValue) != Value)) + { + // Set new value + *((bool*)Param->SetValue) = Value; + + // Mark change + Param->SetChanged = true; + } + break; + case dtSigned16 : if (Force || (*((int16_t*)Param->SetValue) != Value)) { @@ -1369,6 +1443,7 @@ bool CDeviceCore::SetValue( TDeviceParam * Param, const char * Value, const int // Convert to correct type switch (Param->DataType) { + case dtBool : case dtUnsigned16 : case dtUnsigned32_HL : case dtUnsigned32_LH : @@ -1413,6 +1488,10 @@ bool CDeviceCore::GetValue( TDeviceParam * Param, char * Value, int &Len ) // Check if return value longer than actual value switch (Param->DataType) { + case dtBool : + sprintf( Value, "%u", (*((bool*)Param->Value)) ); + break; + case dtUnsigned16 : sprintf( Value, "%u", (*((u_int16_t*)Param->Value)) ); break; @@ -1706,6 +1785,10 @@ bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) char Message[200]; switch (Param->DataType) { + case dtBool : + sprintf( Message, "%s: %u\n", Param->Name, *((bool*)Param->Value) ); + break; + case dtUnsigned16 : sprintf( Message, "%s: %u\n", Param->Name, *((u_int16_t*)Param->Value) ); break; diff --git a/DeviceCore.h b/DeviceCore.h index 9f43f95..2032d67 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -18,12 +18,12 @@ //--------------------------------------------------------------------------- // Enumerated types -typedef enum { dtNone = 0, dtUnsigned16 = 1, dtSigned16 = 2, dtUnsigned32_HL = 3, dtUnsigned32_LH = 4, - dtSigned32_HL = 5, dtSigned32_LH = 6, dtFloat32_L = 7, dtFloat32_B = 8, dtString = 9 } EDeviceDataType; +typedef enum { dtNone = 0, dtBool = 1, dtUnsigned16 = 2, dtSigned16 = 3, dtUnsigned32_HL = 4, dtUnsigned32_LH = 5, + dtSigned32_HL = 6, dtSigned32_LH = 7, dtFloat32_L = 8, dtFloat32_B = 9, dtString = 10 } EDeviceDataType; // Constants const char DataTypeCount = 10; -const char DataTypeName[][20] = { "None", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH", +const char DataTypeName[][20] = { "None", "Boolean", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH", "Signed32_HL", "Signed32_LH", "Float32_L", "Float32_B", "String" }; //--------------------------------------------------------------------------- @@ -232,11 +232,7 @@ protected: Param = &((*Param)->Next); return Param; } - inline TDeviceParamGroup * GetNextParamGroup( TDevice * Device, TDeviceParamGroup * LastParamGroup = NULL ) { - if (!Device) return NULL; - TDeviceParamGroup * ParamGroup = (LastParamGroup)? LastParamGroup->NextGroup : Device->FirstParamGroup; - return ParamGroup; - } + inline TDeviceParam * GetNextReadParam( TDevice * Device, TDeviceParam * LastParam = NULL ) { if (!Device) return NULL; TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam; @@ -276,6 +272,12 @@ protected: return Group; } + inline TDeviceParamGroup * GetNextParamGroup( TDevice * Device, TDeviceParamGroup * LastParamGroup = NULL ) { + if (!Device) return NULL; + TDeviceParamGroup * ParamGroup = (LastParamGroup)? LastParamGroup->NextGroup : Device->FirstParamGroup; + return ParamGroup; + } + // Find Param Groups Items inline TDeviceParamItem * GetParamItem( TDeviceParamGroup * Group, const char * ParamName ) { TDeviceParamItem ** Item = GetParamItemPtr( Group, ParamName ); From 91a7707fef2e987e8f87f20ef6221b1440211f05 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Fri, 12 Jul 2019 08:54:06 +0200 Subject: [PATCH 20/24] Minor Update: - DeviceCore: Issue event with DataPath, not param name --- DeviceCore.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index d8dfc0f..47da2b4 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -1764,6 +1764,8 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * SourceRef, // Generate Event output bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) { + char Message[200]; + // Validate if (!Param || !(Param->EventChannel)) return false; @@ -1773,38 +1775,37 @@ bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) (Param->EventInterval && Timeout( Param->EventTimeout, Param->EventInterval )) ) { // Post event - char Message[200]; switch (Param->DataType) { case dtBool : - sprintf( Message, "%s: %u\n", Param->Name, *((bool*)Param->Value) ); + sprintf( Message, "%s: %u\n", Param->DataPath, *((bool*)Param->Value) ); break; case dtUnsigned16 : - sprintf( Message, "%s: %u\n", Param->Name, *((u_int16_t*)Param->Value) ); + sprintf( Message, "%s: %u\n", Param->DataPath, *((u_int16_t*)Param->Value) ); break; case dtUnsigned32_HL : case dtUnsigned32_LH : - sprintf( Message, "%s: %u\n", Param->Name, *((u_int32_t*)Param->Value) ); + sprintf( Message, "%s: %u\n", Param->DataPath, *((u_int32_t*)Param->Value) ); break; case dtSigned16 : - sprintf( Message, "%s: %d\n", Param->Name, *((int16_t*)Param->Value) ); + sprintf( Message, "%s: %d\n", Param->DataPath, *((int16_t*)Param->Value) ); break; case dtSigned32_HL : case dtSigned32_LH : - sprintf( Message, "%s: %d\n", Param->Name, *((int32_t*)Param->Value) ); + sprintf( Message, "%s: %d\n", Param->DataPath, *((int32_t*)Param->Value) ); break; case dtFloat32_L : case dtFloat32_B : - sprintf( Message, "%s: %f\n", Param->Name, *((float*)Param->Value) ); + sprintf( Message, "%s: %f\n", Param->DataPath, *((float*)Param->Value) ); break; case dtString : - sprintf( Message, "%s: %s\n", Param->Name, (char*)Param->Value ); + sprintf( Message, "%s: %s\n", Param->DataPath, (char*)Param->Value ); break; default : From df371d4f105eb7a5e37e6f7386d46ebe434bac8d Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 15 Jul 2019 17:29:45 +0200 Subject: [PATCH 21/24] Important Update: - DeviceCore: - Allow different event output types: None, Simple or JSON - Add date & time to JSON events --- DeviceCore.cpp | 132 ++++++++++++++++++++++++++++++++++++++----------- DeviceCore.h | 18 ++++++- 2 files changed, 118 insertions(+), 32 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 47da2b4..17b635f 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -13,6 +13,7 @@ // redA Libraries #include "ApplicationCore.h" #include "DeviceCore.h" +#include "DateTimeCore.h" //--------------------------------------------------------------------------- @@ -35,6 +36,7 @@ CDeviceCore::CDeviceCore( const char * pName, const char * pType ) : CFunctionCo // Data Structures ConfigTypes = new CDataMember(); ValueTree = new CDataMember(); + EventData = new CDataMember(); JSONparse = new CJSONparse(); } //--------------------------------------------------------------------------- @@ -52,6 +54,8 @@ CDeviceCore::~CDeviceCore() delete ConfigTypes; if (ValueTree) delete ValueTree; + if (EventData) + delete EventData; } //--------------------------------------------------------------------------- @@ -61,6 +65,7 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) CDataMember * PollConfig = NULL; int IntVal1; int IntVal2; + char * StrVal; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) @@ -105,6 +110,13 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) ProcessName, Name, PersistFile ); } + // Event Output + StrVal = (char*)Config->GetChStr( "EventOutput", "None", true ); + EventOutputType = GetEventType( StrVal ); + + Log->Message( LogLevel, dlMedium, "%s/%s: Event Output - Type:%s", + ProcessName, Name, EventTypeName[EventOutputType] ); + // Update Devices -- may want to do it from derived class intead if (DeviceInit) { InitDevices( FunctionConfig ); @@ -1764,54 +1776,114 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * SourceRef, // Generate Event output bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) { - char Message[200]; + int EventLen = EventMsgLen; + CDataMember * Path = NULL; // Validate if (!Param || !(Param->EventChannel)) return false; + if (EventOutputType == et_None) + return false; // Check Timer or force if (Force || (Param->EventInterval && Timeout( Param->EventTimeout, Param->EventInterval )) ) { + // Create message // Post event - switch (Param->DataType) - { - case dtBool : - sprintf( Message, "%s: %u\n", Param->DataPath, *((bool*)Param->Value) ); - break; + if (true) { + // JSON output + EventData->Clear(); + EventData->SetChStr( "Type", "ParamEvent" ); + EventData->SetChStr( "Time", GetDateTimeStr() ); - case dtUnsigned16 : - sprintf( Message, "%s: %u\n", Param->DataPath, *((u_int16_t*)Param->Value) ); - break; + Path = EventData->GetChild( "Path", true ); + Path->SetArray(); + bool NewMember = true; + char * Start = NULL; + char * Pos = Param->DataPath; + while (true) { + if (!*Pos || (*Pos == '/')) { + NewMember = true; + if (Start) + Path->SetChStr( "[]", Start, Pos-Start ); + if (!*Pos) + break; + } + else if (NewMember) { + NewMember = false; + Start = Pos; + } + Pos++; + } + EventData->SetChStr( "Device", Param->Device->Name ); + EventData->SetChStr( "Param", Param->Name ); - case dtUnsigned32_HL : - case dtUnsigned32_LH : - sprintf( Message, "%s: %u\n", Param->DataPath, *((u_int32_t*)Param->Value) ); - break; + switch (Param->DataType) { + case dtBool : EventData->SetChBool( "Value", *((bool*)Param->Value) ); + break; - case dtSigned16 : - sprintf( Message, "%s: %d\n", Param->DataPath, *((int16_t*)Param->Value) ); - break; + case dtUnsigned16 : EventData->SetChBool( "Value", *((u_int16_t*)Param->Value) ); + break; - case dtSigned32_HL : - case dtSigned32_LH : - sprintf( Message, "%s: %d\n", Param->DataPath, *((int32_t*)Param->Value) ); - break; + case dtUnsigned32_HL : + case dtUnsigned32_LH : EventData->SetChBool( "Value", *((u_int32_t*)Param->Value) ); + break; - case dtFloat32_L : - case dtFloat32_B : - sprintf( Message, "%s: %f\n", Param->DataPath, *((float*)Param->Value) ); - break; + case dtSigned16 : EventData->SetChBool( "Value", *((int16_t*)Param->Value) ); + break; - case dtString : - sprintf( Message, "%s: %s\n", Param->DataPath, (char*)Param->Value ); - break; + case dtSigned32_HL : + case dtSigned32_LH : EventData->SetChBool( "Value", *((int32_t*)Param->Value) ); + break; - default : - break; + case dtFloat32_L : + case dtFloat32_B : EventData->SetChBool( "Value", *((float*)Param->Value) ); + break; + + case dtString : EventData->SetChBool( "Value", (char*)Param->Value ); + break; + + default : EventData->SetChNull( "Value" ); + break; + } + JSONparse->SetBase( EventData ); + JSONparse->WriteToString( NULL, EventMsg, EventLen, 0 ); } - Output( Param->EventChannel, NULL, true, Message, strlen(Message) ); + else { + switch (Param->DataType) + { + case dtBool : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((bool*)Param->Value) ); + break; + + case dtUnsigned16 : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int16_t*)Param->Value) ); + break; + + case dtUnsigned32_HL : + case dtUnsigned32_LH : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int32_t*)Param->Value) ); + break; + + case dtSigned16 : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int16_t*)Param->Value) ); + break; + + case dtSigned32_HL : + case dtSigned32_LH : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int32_t*)Param->Value) ); + break; + + case dtFloat32_L : + case dtFloat32_B : sprintf( EventMsg, "%s: %f\n", Param->DataPath, *((float*)Param->Value) ); + break; + + case dtString : sprintf( EventMsg, "%s: %s\n", Param->DataPath, (char*)Param->Value ); + break; + + default : sprintf( EventMsg, "%s:\n", Param->DataPath ); + break; + } + } + + // Send event + Output( Param->EventChannel, NULL, true, EventMsg, strlen(EventMsg) ); // Reset timer if (Param->EventInterval) { diff --git a/DeviceCore.h b/DeviceCore.h index 655db1c..2cfb8cc 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -20,12 +20,14 @@ // Enumerated types typedef enum { dtNone = 0, dtBool = 1, dtUnsigned16 = 2, dtSigned16 = 3, dtUnsigned32_HL = 4, dtUnsigned32_LH = 5, dtSigned32_HL = 6, dtSigned32_LH = 7, dtFloat32_L = 8, dtFloat32_B = 9, dtString = 10 } EDeviceDataType; - -// Constants const char DataTypeCount = 10; const char DataTypeName[][20] = { "None", "Boolean", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH", "Signed32_HL", "Signed32_LH", "Float32_L", "Float32_B", "String" }; +typedef enum { et_None = 0, et_Simple = 1, et_JSON = 2 } EEventType; +const char EventTypeCount = 3; +const char EventTypeName[][10] = { "None", "Simple", "JSON" }; + //--------------------------------------------------------------------------- // Structure prototypes @@ -152,6 +154,12 @@ protected: int PollRetry = 0; // No of polling retries that has timed out int MaxRetries = 3; // Max allowed retries + // Event output + EEventType EventOutputType = et_None; + CDataMember * EventData = NULL; + const int EventMsgLen = 1000; + char EventMsg[1000] = {0}; + // Manage Devices bool DestroyDevice( TDevice ** Device ); @@ -298,6 +306,12 @@ protected: if (!strcasecmp( TypeName, DataTypeName[Type])) break; return (Type == DataTypeCount)? dtNone : (EDeviceDataType)Type; } + inline EEventType GetEventType( const char * TypeName ) { + int Type; + for (Type = 0; Type < EventTypeCount; Type++) + if (!strcasecmp( TypeName, EventTypeName[Type])) break; + return (Type == EventTypeCount)? et_None : (EEventType)Type; + } bool CompareParamString( const char * ParamValue, const int ParamLen, const char * Value, const int Len ); From 14982e84592232e328482daff66171114cf97b23 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 15 Jul 2019 17:40:40 +0200 Subject: [PATCH 22/24] Important Update: - Channels (FunctionCore & SelectableBare): - Added state "Standby", allow auto-managed handle to be opened - SelectableCore: - Set default "Persistent" state for sockets based on type - Remove Process() method (no different from SelectableBare - DateTimeCore: - Added BuildDateTimeStr() methods to build date for values - JSONparseCore: - Added error message to file operations --- DateTimeCore.cpp | 51 ++++++++++++++++++-------- DateTimeCore.h | 10 ++++-- FunctionCore.h | 4 +-- JSONparseCore.cpp | 5 +-- SelectableBare.cpp | 12 +++++-- SelectableCore.cpp | 89 ++++++++++++++-------------------------------- SelectableCore.h | 1 - 7 files changed, 86 insertions(+), 86 deletions(-) diff --git a/DateTimeCore.cpp b/DateTimeCore.cpp index 8340054..ee3cf3b 100644 --- a/DateTimeCore.cpp +++ b/DateTimeCore.cpp @@ -371,6 +371,40 @@ bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned cha } //--------------------------------------------------------------------------- +char const * BuildDateStr( unsigned char Day, unsigned char Month, unsigned Year, const char * DateSeparator ) +{ + // Build String + sprintf( ReturnStr, "%04d%s%02d%s%02d", + Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day ); + + // Return value + return (ReturnStr); +} +//--------------------------------------------------------------------------- + +char const * BuildTimeStr( unsigned char Hours, unsigned char Minutes, unsigned char Seconds, const char * TimeSeparator ) +{ + // Build String + sprintf( ReturnStr, "%02d%s%02d%s%02d", + Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); + + return (ReturnStr); +} +//--------------------------------------------------------------------------- + +char const * BuildDateTimeStr( unsigned char Day, unsigned char Month, unsigned Year, + unsigned char Hours, unsigned char Minutes, unsigned char Seconds, + const char * DateSeparator, const char * TimeSeparator ) +{ + // Build String + sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", + Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day, + Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); + + return (ReturnStr); +} +//--------------------------------------------------------------------------- + // Get the current date in a string char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator ) { @@ -382,11 +416,7 @@ char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * ReadDate( EpochTime, LocalTime, Day, Month, Year ); // Build String - sprintf( ReturnStr, "%04d%s%02d%s%02d", - Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day ); - - // Return value - return (ReturnStr); + return BuildTimeStr( Year, Month, Day, DateSeparator ); } //--------------------------------------------------------------------------- @@ -400,10 +430,7 @@ char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * ReadTime( EpochTime, LocalTime, Hours, Minutes, Seconds ); // Build String - sprintf( ReturnStr, "%02d%s%02d%s%02d", - Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); - - return (ReturnStr); + return BuildTimeStr( Hours, Minutes, Seconds, TimeSeparator ); } //--------------------------------------------------------------------------- @@ -420,9 +447,5 @@ char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const cha ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds ); // Build String - sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", - Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day, - Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); - - return (ReturnStr); + return BuildDateTimeStr( Year, Month, Day, Hours, Minutes, Seconds, DateSeparator, TimeSeparator ); } diff --git a/DateTimeCore.h b/DateTimeCore.h index e3992c3..b734c40 100644 --- a/DateTimeCore.h +++ b/DateTimeCore.h @@ -39,10 +39,16 @@ bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, un bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); -bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ); +bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false ); bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year ); bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year, - unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ); + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false ); + +char const * BuildDateStr( unsigned char Day, unsigned char Month, unsigned Year, const char * DateSeparator = "/" ); +char const * BuildTimeStr( unsigned char Hours, unsigned char Minutes, unsigned char Seconds, const char * TimeSeparator = ":" ); +char const * BuildDateTimeStr( unsigned char Day, unsigned char Month, unsigned Year, + unsigned char Hours, unsigned char Minutes, unsigned char Seconds, + const char * DateSeparator = "/", const char * TimeSeparator = ":" ); char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/" ); char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator = ":" ); diff --git a/FunctionCore.h b/FunctionCore.h index f17bfec..c274f5c 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -18,8 +18,8 @@ //--------------------------------------------------------------------------- // Enumarate Types -typedef enum { CH_off = 0, CH_wait = 1, CH_ready = 2 } EChannelState; -const char ChannelStateName[][15] = { "Off", "Waiting", "Ready" }; +typedef enum { CH_off = 0, CH_standby = 1, CH_wait = 2, CH_ready = 3 } EChannelState; +const char ChannelStateName[][15] = { "Off", "Standby", "Waiting", "Ready" }; //--------------------------------------------------------------------------- diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index 1cb53a1..cbf39c4 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -8,6 +8,7 @@ // Standard C/C++ Libraries #include #include +#include // redA Libraries #include "JSONparseCore.h" @@ -145,7 +146,7 @@ bool CJSONparse::WriteToFile( const char * BasePath, const char * FilePath, cons // Open file if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC, 0660 )) < 0) { Error = true; - sprintf( ErrorText, "Could not open file" ); + sprintf( ErrorText, "Could not open file - [%d] %s", errno, strerror(errno) ); return false; } @@ -243,7 +244,7 @@ bool CJSONparse::ReadFromFile( const char * BasePath, const char * FilePath ) // Open file if ((Handle = open( FilePath, O_RDONLY )) < 0) { Error = true; - sprintf( ErrorText, "Could not open file" ); + sprintf( ErrorText, "Could not open file - [%d] %s", errno, strerror(errno) ); return false; } diff --git a/SelectableBare.cpp b/SelectableBare.cpp index cddcfac..07e3994 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -175,7 +175,7 @@ bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) if (!Handle || (Handle->State == State)) return false; - // Set Call back + // Execute call back for state if (Handle->StateCallback[ (int)State ]) (Handle->StateCallback[ (int)State ])( this, Handle, State ); @@ -188,6 +188,8 @@ bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) ChannelState = CH_wait; else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting)) ChannelState = CH_ready; + else if (Handle->AutoManage) + ChannelState = CH_standby; else ChannelState = CH_off; if (Handle->Channel->InState != ChannelState) @@ -677,9 +679,9 @@ int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, co ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (Channel->InState != CH_ready) { + else if (Channel->InState == CH_off) { // Channel disabled - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel off", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } @@ -822,6 +824,10 @@ bool CSelectableBare::Process() Open( Handle ); } } + else if (Handle->Channel && (Handle->Channel->InState == CH_off) && Handle->AutoManage) { + // Set channel to standby + SetChannelInState( Handle->Channel, CH_standby ); + } // Check Input buffers if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) { diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 4703eaa..814f2e5 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -114,6 +114,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) short Parity; short FlowCtrl; short Queue; + bool Persitent; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) @@ -170,6 +171,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) SerialConfig->GetChInt( "DataBits", 8, true ), Parity, SerialConfig->GetChInt( "StopBits", 1, true ), FlowCtrl, SerialConfig->GetChInt( "DataWait", 0, true )); + Persitent = true; } } else if (!strcasecmp( Type, "LinePrinter" )) @@ -180,6 +182,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Port/Address", NULL, true ); // Get default value } SetLinePrinterHandle( Handle, Address ); + Persitent = true; } else if (!strcasecmp( Type, "UNIXserver" )) { @@ -190,6 +193,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) } Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true ); SetUnixHandle( Handle, ctUNIXserver, Address, Queue ); + Persitent = true; } else if (!strcasecmp( Type, "UNIXclient" )) { @@ -199,69 +203,75 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value } SetUnixHandle( Handle, ctUNIXclient, Address, 0 ); + Persitent = false; } else if (!strcasecmp( Type, "UDPserver" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0 ); + Persitent = true; } else if (!strcasecmp( Type, "UDPclient" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0 ); + Persitent = false; } else if (!strcasecmp( Type, "TCPserver" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true ); SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Queue ); + Persitent = true; } else if (!strcasecmp( Type, "TCPclient" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0 ); + Persitent = false; } else if (!strcasecmp( Type, "ForkPipe" )) { Address = (char*)HandleConfig->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value SetForkPipeHandle( Handle, Address ); + Persitent = true; } // Set Auto Manage - SetAutoManage( Handle, HandleConfig->GetChBool( "AutoManage/Enabled", true, true ), - HandleConfig->GetChBool( "AutoManage/Persistent", false, true ), - HandleConfig->GetChInt( "AutoManage/ReopenDelay", 2000, true ), - HandleConfig->GetChInt( "AutoManage/CloseTimeout", 2000, true )); + SetAutoManage( Handle, HandleConfig->GetChBool( "AutoManage/Enabled", true, true ), + HandleConfig->GetChBool( "AutoManage/Persistent", Persitent, true ), + HandleConfig->GetChInt( "AutoManage/ReopenDelay", 2000, true ), + HandleConfig->GetChInt( "AutoManage/CloseTimeout", 2000, true )); // Input buffer - SetInBuffer( Handle, HandleConfig->GetChInt( "InputBuffer/Size", 0 ), - HandleConfig->GetChInt( "InputBuffer/Timeout", 250 ), - HandleConfig->GetChStr( "InputBuffer/Marker", "" ), - HandleConfig->GetChInt( "InputBuffer/MarkerLen", 0 ) ); - SetOutBuffer( Handle, HandleConfig->GetChInt( "OutputBuffer/Size", 0 ) ); + SetInBuffer( Handle, HandleConfig->GetChInt( "InputBuffer/Size", 0 ), + HandleConfig->GetChInt( "InputBuffer/Timeout", 250 ), + HandleConfig->GetChStr( "InputBuffer/Marker", "" ), + HandleConfig->GetChInt( "InputBuffer/MarkerLen", 0 ) ); + SetOutBuffer( Handle, HandleConfig->GetChInt( "OutputBuffer/Size", 0 ) ); // Next HandleConfig = HandleConfig->GetNextPeer(); @@ -2330,51 +2340,6 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len } //--------------------------------------------------------------------------- -bool CSelectableCore::Process() -{ - THandle * Handle = NULL; - - // Process all Handles - Handle = FirstHandle; - while (Handle) - { - // Auto manage handles - if (Handle->State == csPrepared) { - // Proceed to open - Open( Handle ); - } - else if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) { - // Try to re-open port after delay - if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { - Open( Handle ); - } - } - - // Check Input buffers - if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) { - // Check duration since last PortIn - if (Timeout( Handle->InStart, Handle->InTimeout )) { - // Process Input - ProcessInputBuffer( Handle, true ); - - // Reset timer - ClearStartTime( &(Handle->InStart) ); - } - } - - // Check for auto close (but not on servers) - if ((Handle->State == csOpen) && Handle->AutoManage && !Handle->Persistent && (Handle->Type != ctTCPserver) && (Handle->Type != ctUNIXserver)) { - // Close port after timeout - if (Timeout( Handle->LastAction, Handle->CloseTimeout )) { - Close( Handle, true ); - } - } - Handle = Handle->Next; - } - return true; -} -//--------------------------------------------------------------------------- - // Set serial port configuration parameters bool CSelectableCore::WriteSerialConfig( THandle * Handle ) { diff --git a/SelectableCore.h b/SelectableCore.h index 24d2d51..67a8207 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -365,7 +365,6 @@ public: // Function Interface virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); - virtual bool Process(); friend void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ); }; From fb28f86ae93d59a47cad2ff8f3f5b3c97312ec0c Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Tue, 16 Jul 2019 16:43:55 +0200 Subject: [PATCH 23/24] Important Update: - JSONparse: - Allow base entry to be Array or Object - Do not enforce escaping of '/' -> '\/' - Bug fix: properly encode string values in arrays --- JSONparseCore.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index cbf39c4..ef35ed0 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -352,11 +352,11 @@ bool CJSONparse::ReadFromBuffer( const char * BasePath ) // Parse Root Object SkipWhiteSpace(); - if (!ParseObject( BaseMember )) { + if (!ParseObject( BaseMember ) && !Error && !ParseArray( BaseMember )) { if (!Error) { Error = true; CharNo += BufPos-Mark; - sprintf( ErrorText, "First entry in file must be an Object on line %d:%d", LineNo, CharNo ); + sprintf( ErrorText, "First entry in file must be an Object or Array on line %d:%d", LineNo, CharNo ); } FreeBuffer(); return false; @@ -475,7 +475,7 @@ bool CJSONparse::ParseString( char ** Value, int &Len ) while (true) { // Check for special characters - if ((EndMark = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" ))) { + if ((EndMark = strpbrk( BufPos, "\"\\\n\t\b\f\n\r" ))) { /*"\"/\\\n\t\b\f\n\r" (forward slash included)*/ BufPos = EndMark; } else if (RefillBuffer) { FillBuffer(); @@ -816,7 +816,7 @@ bool CJSONparse::PrintString( char * String, int Len ) { // Scan for special chars Mark = BufPos; - while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && (*BufPos != '/') && (*BufPos != '"')) + while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && /*(*BufPos != '/') &&*/ (*BufPos != '"')) BufPos++; // Print Portion @@ -1029,9 +1029,7 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent ) break; case jtString : - if ((Print( this, "\"", 1 ) < 0) || - (Print( this, Member->Value, Member->Len ) < 0) || - (Print( this, "\"", 1 ) < 0)) + if (!PrintString( Member->Value, Member->Len )) return false; break; From 55168dece29bf6ecee2e27d67d2744ab119f632e Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 22 Jul 2019 10:59:24 +0200 Subject: [PATCH 24/24] Important update: - DateTimeCore: - Bug fix: BuildDateTimeStr() incorrect date - New methods: ReadDateTime() convert DateTimeStr -> time_t --- DateTimeCore.cpp | 27 +++++++++++++++++++++++++-- DateTimeCore.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/DateTimeCore.cpp b/DateTimeCore.cpp index ee3cf3b..1aa388f 100644 --- a/DateTimeCore.cpp +++ b/DateTimeCore.cpp @@ -293,6 +293,29 @@ bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, u } //--------------------------------------------------------------------------- +bool ReadDateTime( const char * DateTimeStr, bool LocalTime, time_t &EpochTime ) +{ + int ItemsAssigned; + struct tm NewTime; + + // Read time + ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d", + &(NewTime.tm_year), &(NewTime.tm_mon), &(NewTime.tm_mday), + &(NewTime.tm_hour), &(NewTime.tm_min), &(NewTime.tm_sec) ); + if (ItemsAssigned != 6) + return false; + + // Update time + NewTime.tm_year -= 1900; + NewTime.tm_mon -= 1; + NewTime.tm_zone = "UTC"; + + // Convert to Epoch Time + EpochTime = mktime( &NewTime ) + ((LocalTime)? 0 : NewTime.tm_gmtoff); + return true; +} +//--------------------------------------------------------------------------- + // Read components from date/time string bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ) { @@ -416,7 +439,7 @@ char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * ReadDate( EpochTime, LocalTime, Day, Month, Year ); // Build String - return BuildTimeStr( Year, Month, Day, DateSeparator ); + return BuildDateStr( Day, Month, Year, DateSeparator ); } //--------------------------------------------------------------------------- @@ -447,5 +470,5 @@ char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const cha ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds ); // Build String - return BuildDateTimeStr( Year, Month, Day, Hours, Minutes, Seconds, DateSeparator, TimeSeparator ); + return BuildDateTimeStr( Day, Month, Year, Hours, Minutes, Seconds, DateSeparator, TimeSeparator ); } diff --git a/DateTimeCore.h b/DateTimeCore.h index b734c40..1fe92ff 100644 --- a/DateTimeCore.h +++ b/DateTimeCore.h @@ -39,6 +39,8 @@ bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, un bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds ); +bool ReadDateTime( const char * DateTimeStr, bool LocalTime, time_t &EpochTime ); + bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false ); bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year ); bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year,