diff --git a/ApplicationCore.cpp b/ApplicationCore.cpp index 3f6a1b4..5c90216 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 ); @@ -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; } } 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/DateTimeCore.cpp b/DateTimeCore.cpp index 628401e..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,15 +268,118 @@ bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, } //--------------------------------------------------------------------------- +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 + if (LocalTime) + localtime_r( &EpochTime, &CurrentTime ); + else + gmtime_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 >= 3)? 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 >= 3)? 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 >= 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", @@ -223,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", @@ -240,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; @@ -250,8 +417,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, 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 dea4957..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,12 +33,20 @@ 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 ); +// 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 ); -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 = ":" ); +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, 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 7616beb..d8dfc0f 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(); @@ -69,7 +58,6 @@ CDeviceCore::~CDeviceCore() bool CDeviceCore::Init( CDataMember * FunctionConfig ) { char * PersistFile = NULL; - char * ConfigName = NULL; CDataMember * PollConfig = NULL; int IntVal1; int IntVal2; @@ -80,18 +68,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) // Add Channels if (!(CmdChannel = GetChannel( "Command" ))) - CmdChannel = AddChannel( "Command", true, true ); - if (!(DeviceChannel = GetChannel( "Device" ))) - DeviceChannel = AddChannel( "Device", true, true ); - if (!(EventChannel = GetChannel( "Event" ))) - EventChannel = AddChannel( "Event", true, true ); + CmdChannel = AddChannel( "Command", CH_ready ); + else + SetChannelInState( CmdChannel, CH_ready ); - // Get configuration - if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) { - ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); - Config = Application->Config->GetChild( ConfigName, true ); - } - if (Config->isNull()) Config->SetObject(); + if (!(DeviceChannel = GetChannel( "Device" ))) + DeviceChannel = AddChannel( "Device", CH_ready ); + else + SetChannelInState( DeviceChannel, CH_ready ); + + if (!(EventChannel = GetChannel( "Event" ))) + EventChannel = AddChannel( "Event", CH_ready ); + else + SetChannelInState( EventChannel, CH_ready ); // Load Polling configuration PollConfig = Config->GetChild( "Polling", true ); @@ -442,6 +431,7 @@ bool CDeviceCore::SetPollParam( int pPollInterval ) bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries ) { + DefReplyTimeout = pReplyTimeout; ReplyTimeout = pReplyTimeout; MaxRetries = pMaxRetries; return true; @@ -466,12 +456,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; } @@ -1622,7 +1613,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]; @@ -1671,7 +1662,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) ); } } @@ -1680,7 +1671,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 )) @@ -1717,7 +1708,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 ); } } @@ -1726,7 +1717,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 )) @@ -1746,7 +1737,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 @@ -1754,7 +1745,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 @@ -1764,7 +1755,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; } @@ -1819,7 +1810,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/DeviceCore.h b/DeviceCore.h index 2032d67..655db1c 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -121,11 +121,10 @@ class CDeviceCore : public CFunctionCore { protected: // Configuration - CDataMember * Config = NULL; - 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; @@ -133,24 +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 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 ); @@ -309,7 +309,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(); @@ -389,7 +389,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/FileCore.cpp b/FileCore.cpp index 6a96902..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 ); + AddChannel( Name, CH_ready ); } // Set Parameters @@ -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-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/FunctionCore.cpp b/FunctionCore.cpp index b8da187..d60ab65 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; @@ -44,35 +43,19 @@ CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( p CFunctionCore::~CFunctionCore() { TChannel * NextChannel = NULL; - TChannelLink * NextLinkedChannel = NULL; // Destroy Channels while (FirstChannel) { + // Destroy Linked Channels + while (FirstChannel->FirstLink) + UnlinkChannel( FirstChannel->Name, FirstChannel->FirstLink->Function->Name, FirstChannel->FirstLink->Channel->Name ); + // Destroy Parameters - if (FirstChannel->Name) { + 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; - } - - // Destroy Linked Outputs - while (FirstChannel->FirstOutput) { - if (FirstChannel->FirstOutput->Name) { - free( FirstChannel->FirstOutput->Name ); - } - NextLinkedChannel = FirstChannel->FirstOutput->Next; - delete FirstChannel->FirstOutput; - FirstChannel->FirstOutput = NextLinkedChannel; - } + if (FirstChannel->Ref) + free( FirstChannel->Ref ); // Destroy Channel NextChannel = FirstChannel->Next; @@ -95,11 +78,15 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) CDataMember * ChannelConfig; EDebugLevel pLogLevel; int pLogOutput; + char * ConfigName = NULL; // Validate if (!FunctionConfig ) return false; + // Set Type + FunctionConfig->SetChStr( "Type", Type ); + // Configure Logging/Debugging LogConfig = FunctionConfig->GetChild( "Log", true ); pLogLevel = Log->ReadLogLevel( LogConfig ); @@ -108,16 +95,17 @@ 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(), CH_off ); ChannelConfig = ChannelConfig->GetNextPeer(); } + // Get main configuration + if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) { + ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); + Config = Application->Config->GetChild( ConfigName, true ); + } + return true; } //--------------------------------------------------------------------------- @@ -142,10 +130,11 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig ) while (FunctionMember) { // Get Parameters - LinkOutputChannel( Channel->Name, - FunctionMember->GetChStr( "Function" ), - FunctionMember->GetChStr( "Channel" ), - FunctionMember->GetChBool( "Bidirectional" ) ); + LinkChannel( Channel->Name, + FunctionMember->GetChStr( "Function", NULL, true ), + FunctionMember->GetChStr( "Channel", NULL, true ), + FunctionMember->GetChBool( "Input", false, true ), + FunctionMember->GetChBool( "Output", false, true ) ); FunctionMember = FunctionMember->GetNextPeer(); } } @@ -173,7 +162,7 @@ bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel ) } //--------------------------------------------------------------------------- -TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInputEnable, const bool pOutputEnable ) +TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelState State ) { TChannel ** Channel = NULL; @@ -195,166 +184,263 @@ 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)->InState = State; + (*Channel)->OutState = CH_off; // 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', In:%s, Out:%s", + ProcessName, Name, ChannelName, (*Channel)->Ref, + ChannelStateName[(*Channel)->InState], ChannelStateName[(*Channel)->OutState]); } - - // Set parameters - (*Channel)->InputEnabled = pInputEnable; - (*Channel)->OutputEnabled = pOutputEnable; - return *Channel; } //--------------------------------------------------------------------------- -// Automated Data Input/Output -bool CFunctionCore::LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional ) +bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State ) { - CFunctionCore * OutFunction = NULL; - TChannel * Channel = NULL; - TChannelLink ** LinkedChannel = NULL; + EChannelState OldState = Channel->InState; + TChannelLink * LinkChannel; - // Get Channel - if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) { + // Validate + if (!Channel) return false; - } - // Check if linked Channel exists - LinkedChannel = &(Channel->FirstInput); - while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) { - LinkedChannel = &((*LinkedChannel)->Next); - } + // Update state + Channel->InState = State; + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s", + ProcessName, Name, Channel->Ref, ChannelStateName[State] ); - // Create if not found - if (!*LinkedChannel) - { - // Create - *LinkedChannel = new TChannelLink; + // 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] ); - // Set Parameters - (*LinkedChannel)->Function = OutFunction; - (*LinkedChannel)->Name = strdup( OutChannelName ); + // Trigger Linked Channel Events + LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel ); + LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State ); - // 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 ); + LinkChannel = LinkChannel->Next; } return true; } //--------------------------------------------------------------------------- -bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ) +bool CFunctionCore::UpdateChannelOutState( TChannel * Channel ) { - TChannel * OutChannel = NULL; - CFunctionCore * InFunction = NULL; - TChannel * InChannel = NULL; + TChannelLink * LinkChannel; + EChannelState OutState; + + // 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->Ref, ChannelStateName[OutState] ); + } + return true; +} +//--------------------------------------------------------------------------- + +EChannelState CFunctionCore::GetChannelOutState( TChannel * Channel, const char * TargetRef ) +{ + TChannelLink * LinkChannel = NULL; + + // Validate + 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; + } +} +//--------------------------------------------------------------------------- + +// 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( InFunctionName )) || - !(InChannel = InFunction->GetChannel( InChannelName )) ) { + if (!(Channel = GetChannel( ChannelName )) || + !(LinkFunction = Application->GetFunction( LinkFunctionName )) || + !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) { return false; } // Check if linked Channel exists - LinkedChannel = &(OutChannel->FirstOutput); - while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) { + 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( InChannelName ); + // 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, InFunction->GetName(), InChannelName ); - } + // 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->LinkOutputChannel( InChannelName, 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") ); + + // Trigger Forward Channel Events + LinkFunction->UpdateChannelOutState( LinkChannel ); + LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState ); + + // Trigger Reverse Channel Events + UpdateChannelOutState( Channel ); + ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState ); return true; } //--------------------------------------------------------------------------- -// Manual Data Input/Output -int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len ) +bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName ) { - TChannel * Channel = NULL; + 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; + } + + // Trigger Channel Events + LinkFunction->UpdateChannelOutState( LinkChannel ); + UpdateChannelOutState( Channel ); + return true; +} +//--------------------------------------------------------------------------- + +int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len ) +{ + 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 ); + 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->InState] ); 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; + TChannelLink * LinkChannel = NULL; int TempLen = 0; int OutLen = 0; @@ -363,123 +449,23 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len, 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 ); - return 0; - } - // Log event - if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:", - ProcessName, Name, Channel->Name ); + 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) { + if (Len == -1) Len = strlen( Data ); - } - OutChannel = Channel->FirstOutput; - while (OutChannel) { - TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len ); - OutLen = (TempLen > OutLen)? TempLen : OutLen; - OutChannel = OutChannel->Next; + 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; + } + LinkChannel = LinkChannel->Next; } // Return processed bytes 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 b04266a..f17bfec 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; @@ -28,12 +34,12 @@ class CFunctionCore; struct SChannel { char * Name = NULL; + char * Ref = NULL; - TChannelLink * FirstInput = NULL; - TChannelLink * FirstOutput = NULL; + TChannelLink * FirstLink = NULL; // List of channels linked for input/output - bool InputEnabled = NULL; - bool OutputEnabled = NULL; + 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; }; @@ -42,7 +48,10 @@ struct SChannel struct SChannelLink { CFunctionCore * Function = NULL; - char * Name = NULL; + TChannel * Channel = NULL; + + bool Input = false; + bool Output = false; SChannelLink * Next = NULL; }; @@ -62,6 +71,9 @@ protected: char * Name = NULL; bool WaitToTerminate = false; + // JSON Config + CDataMember * Config = NULL; + // Channels TChannel * FirstChannel = NULL; @@ -70,10 +82,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; @@ -82,10 +90,16 @@ 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 * 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 @@ -105,39 +119,20 @@ 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 EChannelState State ); + + 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 * 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 Input, bool Output ); + virtual bool UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName ); virtual bool Process() = 0; friend class CApplication; diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index c3cce76..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" ); @@ -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 { 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" }; diff --git a/SelectableBare.cpp b/SelectableBare.cpp index f9aa630..cddcfac 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; } //--------------------------------------------------------------------------- @@ -97,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) { @@ -106,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", @@ -115,7 +113,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh // Create Matching Channel if (CreateChannel) { - (*Handle)->Channel = AddChannel( HandleName ); + (*Handle)->Channel = AddChannel( HandleName, CH_off ); } return *Handle; @@ -162,61 +160,39 @@ 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 ) { + EChannelState ChannelState = CH_off; + // Validate - if (!Handle) { + if (!Handle || (Handle->State == State)) 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; - } + // Set Call back + if (Handle->StateCallback[ (int)State ]) + (Handle->StateCallback[ (int)State ])( this, Handle, State ); - // Reset Parameters - Handle->Type = ctNone; + // Change state + Handle->State = State; - // Log event - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", - ProcessName, Name, Handle->Name ); + // Update Channel + if (Handle->Channel) { + if ((Handle->State == csPreparing) || (Handle->State == csPrepared) || (Handle->State == csWaitingtoOpen)) + ChannelState = CH_wait; + else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting)) + ChannelState = CH_ready; + else + ChannelState = CH_off; + if (Handle->Channel->InState != ChannelState) + SetChannelInState( Handle->Channel, ChannelState ); + } return true; } //--------------------------------------------------------------------------- @@ -322,9 +298,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 @@ -342,9 +318,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 @@ -355,10 +331,11 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force ) } //--------------------------------------------------------------------------- -int CSelectableBare::Open( THandle * Handle, bool DelayResolve ) +int CSelectableBare::Open( THandle * Handle ) { THandle * NewHandle = NULL; + // Validate if (!Handle || (Handle->Type == ctNone)) { return -1; @@ -394,11 +371,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 + HandleState( Handle, csOpen ); return (NewHandle)? NewHandle->FD : -1; }; //--------------------------------------------------------------------------- @@ -414,7 +391,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) @@ -426,15 +412,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 + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- @@ -534,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 ); } } @@ -678,7 +657,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; @@ -694,20 +673,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) { + else if (Channel->InState != CH_ready) { // 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 not Ready", + 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; @@ -725,8 +704,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; } @@ -752,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; } @@ -833,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 ); @@ -863,95 +836,14 @@ 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; } //--------------------------------------------------------------------------- - -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 a54d54c..4703eaa 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -40,24 +40,57 @@ 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 ) { - // Quick access - Selector = Application->Selector; + // 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->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 ); - } + if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) + Close( FirstHandle, false ); NextHandle = FirstHandle->Next; DestroyHandle( FirstHandle ); @@ -81,7 +114,6 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) short Parity; short FlowCtrl; short Queue; - long Delay; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) @@ -177,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" )) { @@ -189,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" )) { @@ -201,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" )) { @@ -214,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 @@ -243,6 +271,87 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) } //--------------------------------------------------------------------------- +bool CSelectableCore::DestroyHandle( THandle * Handle ) +{ + int Result; + + // Validate Handle + if (!Handle) + return false; + + // Destroy Resolve request + 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) ); + } + 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 @@ -353,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 || @@ -364,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) @@ -443,7 +551,7 @@ THandle * CSelectableCore::OpenSerialPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -486,7 +594,7 @@ THandle * CSelectableCore::OpenLinePrinterPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -588,7 +696,7 @@ THandle * CSelectableCore::OpenForkPipe( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -612,7 +720,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -624,7 +732,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -648,7 +756,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) // Set state close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return NULL; }; @@ -662,7 +771,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) // Set state close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return NULL; }; @@ -676,7 +786,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -702,7 +812,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -729,7 +839,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -745,11 +855,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; + HandleState( Handle, csFailed ); return NULL; } } @@ -764,7 +873,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -861,7 +970,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -869,14 +978,19 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) } //--------------------------------------------------------------------------- -bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) +bool CSelectableCore::ResolveAddress( THandle * Handle ) { - struct addrinfo hints; - int result; + struct addrinfo * Hints; + TResolveReq * ResolveReq; + sigevent ResolveEvt; + int Result; + + // Ignore if busy resolving + if (Handle->State == csPreparing) + return false; // Check if resolved address available - if (Handle->AddressInfo) - { + if (Handle->AddressInfo) { // Return if address still valid if (!Handle->AddressFailed) return true; @@ -907,47 +1021,108 @@ 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 (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 ); + // Resolve Host & Port Names + 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) ); + DestroyResolveReq( Handle, true ); + + HandleState( Handle, csFailed ); + SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve + return false; + } + return false; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::DestroyResolveReq( THandle * Handle, bool DestroyResult ) +{ + // Validate + if (!Handle || !Handle->ResolveReq) + return false; + + // 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; + 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 ); + SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve 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 ); - return false; - } + // Read result + Handle->AddressList = Handle->ResolveReq->Request->ar_result; + Handle->AddressInfo = Handle->AddressList; // Select first address, skip "0.0.0.0" - Handle->AddressInfo = Handle->AddressList; 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 ); + SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve return false; } @@ -956,11 +1131,15 @@ 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 ); + HandleState( Handle, csPrepared ); return true; } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle ) { // Validate Handle if (Handle->Type != ctUDPserver) { @@ -968,7 +1147,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso } // Resolve Host & Port Names - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create socket @@ -979,7 +1158,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; }; @@ -994,11 +1173,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 + HandleState( Handle, csFailed ); return NULL; }; @@ -1012,7 +1193,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1042,7 +1223,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; @@ -1074,7 +1255,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) { @@ -1083,7 +1264,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso } // Resolve IP Address - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create File descriptor @@ -1094,7 +1275,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; }; @@ -1111,12 +1292,12 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle ) { // Socket options struct linger ServerLinger_opt; @@ -1135,7 +1316,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso } // Resolve Host & Port Names - if (!ResolveAddress( Handle, DelayResolve )) + if (!ResolveAddress( Handle )) return NULL; // Create socket @@ -1146,7 +1327,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; }; @@ -1159,7 +1340,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; } @@ -1174,7 +1355,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; } @@ -1189,11 +1370,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; + + HandleState( Handle, csFailed ); return NULL; }; @@ -1204,11 +1386,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; + + HandleState( Handle, csFailed ); return NULL; }; @@ -1222,7 +1405,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1270,7 +1453,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) { @@ -1280,7 +1462,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; @@ -1325,7 +1507,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->HostName ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -1333,13 +1515,14 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) } //--------------------------------------------------------------------------- -THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayResolve ) +THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle ) { // 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) { @@ -1350,7 +1533,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 @@ -1361,7 +1544,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; }; @@ -1373,16 +1556,18 @@ 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)", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); - // Set State + // Close handle close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return NULL; } } @@ -1399,7 +1584,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)) @@ -1414,7 +1599,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -1430,17 +1615,16 @@ 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; + HandleState( Handle, csFailed ); return NULL; } } //--------------------------------------------------------------------------- -int CSelectableCore::Open( THandle * Handle, bool DelayResolve ) +int CSelectableCore::Open( THandle * Handle ) { THandle * NewHandle = NULL; @@ -1467,16 +1651,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; @@ -1532,7 +1716,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) @@ -1616,15 +1809,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 + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- @@ -1680,7 +1866,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) { @@ -1842,7 +2028,7 @@ bool CSelectableCore::Write( THandle * Handle ) else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { // Attempt to re-open port - Open( Handle, true ); + Open( Handle ); } } @@ -1856,7 +2042,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) { @@ -2007,11 +2193,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; } @@ -2153,16 +2339,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 ); } } @@ -2471,3 +2655,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..24d2d51 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -10,6 +10,8 @@ // Standard C/C++ Libraries #include +#include +#include // redA Libraries #include "FunctionCore.h" @@ -22,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" }; //--------------------------------------------------------------------------- @@ -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; @@ -88,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 @@ -103,7 +106,8 @@ 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 // Serial Port config bool SerialConfig = false; @@ -132,6 +136,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,8 +206,9 @@ protected: CSelect * Selector = NULL; // Managing File Handles - bool RemoveHandle( THandle * Handle ); - bool DestroyHandle( THandle * Handle ); + 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 ) { @@ -201,15 +216,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 ); @@ -217,9 +223,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++ ) @@ -233,19 +236,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)) @@ -254,7 +255,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 ); @@ -262,17 +263,14 @@ 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 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 )); }; @@ -294,8 +292,8 @@ 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 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(); }; @@ -304,6 +302,8 @@ public: class CSelectableCore : public CSelectableBare { protected: + struct sigaction ResolveAct; + // Port Operations THandle * OpenSerialPort( THandle * Handle ); bool WriteSerialConfig( THandle * Handle ); @@ -318,18 +318,27 @@ protected: THandle * OpenUNIXremoteSocket( THandle * Handle ); // Socket Operations - bool ResolveAddress( THandle * Handle, bool DelayResolve ); - THandle * OpenUDPserverSocket( 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 ); 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 ); 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 ); @@ -339,22 +348,26 @@ 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 ); 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 ); // Function Interface - int OutputHandle( THandle * Handle, const char * Data, int Len ); + 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 ); } //--------------------------------------------------------------------------- diff --git a/TimingCore.h b/TimingCore.h index 8718f6e..14f8ece 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,54 @@ inline long TimePassed( timeval StartTime ) { Duration = LONG_MAX; return Duration; }; +//--------------------------------------------------------------------------- + +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)); }; +//--------------------------------------------------------------------------- // 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; + + // Get duration + Duration = SecondsPassed( StartTime ); + + // 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_ */ diff --git a/UtilCore.cpp b/UtilCore.cpp index 660897c..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; } @@ -75,7 +78,7 @@ char * BytesToHexStr( const char * Bytes, const int Len, const char * Separator, // Print Hex values of individual bytes for (int i=0; i= 'a') && (Digit <= 'f')) return (Digit - 'a'+10); else return 0; } -char * HexStrToBytes( const char * Str, const int Len, const char * Separator, char * OutBuf ); -char * BinStrToBytes( const char * Str, const int Len, const char *Separator = NULL, char * OutBuf = NULL ); +char * HexStrToBytes( const char * Str, const int Len, const char * Separator = NULL, char * OutBuf = NULL ); +char * BinStrToBytes( const char * Str, const int Len, const char * Separator = NULL, char * OutBuf = NULL ); // Search string data char * StrSearch( const char * Haystack, const char * Needle, const int hLen = 0, const int nLen = 0 ); 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" )))