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 0e9a54e..49f221f 100644 --- a/DataTreeCore.cpp +++ b/DataTreeCore.cpp @@ -127,10 +127,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) { @@ -138,7 +136,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..1aa388f 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,16 +268,134 @@ bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, } //--------------------------------------------------------------------------- -// Get the current date in a string -char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator ) +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 ) { - unsigned char Day; - unsigned char Month; - unsigned int Year; + struct tm CurrentTime; - // Get Date - ReadDate( EpochTime, Day, Month, Year ); + // 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; +} +//--------------------------------------------------------------------------- + +bool ReadDateTime( const char * DateTimeStr, bool LocalTime, time_t &EpochTime ) +{ + int ItemsAssigned; + struct tm NewTime; + + // Read time + ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d", + &(NewTime.tm_year), &(NewTime.tm_mon), &(NewTime.tm_mday), + &(NewTime.tm_hour), &(NewTime.tm_min), &(NewTime.tm_sec) ); + if (ItemsAssigned != 6) + return false; + + // Update time + NewTime.tm_year -= 1900; + NewTime.tm_mon -= 1; + NewTime.tm_zone = "UTC"; + + // Convert to Epoch Time + EpochTime = mktime( &NewTime ) + ((LocalTime)? 0 : NewTime.tm_gmtoff); + return true; +} +//--------------------------------------------------------------------------- + +// Read components from date/time string +bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime ) +{ + 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); +} +//--------------------------------------------------------------------------- + +char const * BuildDateStr( unsigned char Day, unsigned char Month, unsigned Year, const char * DateSeparator ) +{ // Build String sprintf( ReturnStr, "%04d%s%02d%s%02d", Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day ); @@ -223,15 +405,8 @@ char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator ) } //--------------------------------------------------------------------------- -char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator ) +char const * BuildTimeStr( unsigned char Hours, unsigned char Minutes, unsigned char Seconds, const char * TimeSeparator ) { - unsigned char Hours; - unsigned char Minutes; - unsigned char Seconds; - - // Get Date & Time - ReadTime( EpochTime, Hours, Minutes, Seconds ); - // Build String sprintf( ReturnStr, "%02d%s%02d%s%02d", Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); @@ -240,7 +415,49 @@ 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( unsigned char Day, unsigned char Month, unsigned Year, + unsigned char Hours, unsigned char Minutes, unsigned char Seconds, + const char * DateSeparator, const char * TimeSeparator ) +{ + // Build String + sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", + Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day, + Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); + + return (ReturnStr); +} +//--------------------------------------------------------------------------- + +// Get the current date in a string +char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator ) +{ + unsigned char Day; + unsigned char Month; + unsigned int Year; + + // Get Date + ReadDate( EpochTime, LocalTime, Day, Month, Year ); + + // Build String + return BuildDateStr( Day, Month, Year, DateSeparator ); +} +//--------------------------------------------------------------------------- + +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, LocalTime, Hours, Minutes, Seconds ); + + // Build String + return BuildTimeStr( Hours, Minutes, Seconds, TimeSeparator ); +} +//--------------------------------------------------------------------------- + +char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator, const char * TimeSeparator ) { unsigned char Day; unsigned char Month; @@ -250,13 +467,8 @@ 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", - Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day, - Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); - - return (ReturnStr); + return BuildDateTimeStr( Day, Month, Year, Hours, Minutes, Seconds, DateSeparator, TimeSeparator ); } diff --git a/DateTimeCore.h b/DateTimeCore.h index dea4957..1fe92ff 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,28 @@ 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 ReadDateTime( const char * DateTimeStr, bool LocalTime, time_t &EpochTime ); + +bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false ); +bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year ); +bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year, + unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false ); + +char const * BuildDateStr( unsigned char Day, unsigned char Month, unsigned Year, const char * DateSeparator = "/" ); +char const * BuildTimeStr( unsigned char Hours, unsigned char Minutes, unsigned char Seconds, const char * TimeSeparator = ":" ); +char const * BuildDateTimeStr( unsigned char Day, unsigned char Month, unsigned Year, + unsigned char Hours, unsigned char Minutes, unsigned char Seconds, + const char * DateSeparator = "/", const char * TimeSeparator = ":" ); + +char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/" ); +char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator = ":" ); +char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" ); //--------------------------------------------------------------------------- diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 056ec7a..17b635f 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -13,12 +13,13 @@ // redA Libraries #include "ApplicationCore.h" #include "DeviceCore.h" +#include "DateTimeCore.h" //--------------------------------------------------------------------------- // Global Vars extern char * ProcessName; -extern CApplication * Application; +//extern CApplication * Application; //--------------------------------------------------------------------------- @@ -30,22 +31,12 @@ 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(); + EventData = new CDataMember(); JSONparse = new CJSONparse(); } //--------------------------------------------------------------------------- @@ -63,6 +54,8 @@ CDeviceCore::~CDeviceCore() delete ConfigTypes; if (ValueTree) delete ValueTree; + if (EventData) + delete EventData; } //--------------------------------------------------------------------------- @@ -72,6 +65,7 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) CDataMember * PollConfig = NULL; int IntVal1; int IntVal2; + char * StrVal; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) @@ -79,11 +73,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) // Add Channels if (!(CmdChannel = GetChannel( "Command" ))) - CmdChannel = AddChannel( "Command", true, true ); + CmdChannel = AddChannel( "Command", CH_ready ); + else + SetChannelInState( CmdChannel, CH_ready ); + if (!(DeviceChannel = GetChannel( "Device" ))) - DeviceChannel = AddChannel( "Device", true, true ); + DeviceChannel = AddChannel( "Device", CH_ready ); + else + SetChannelInState( DeviceChannel, CH_ready ); + if (!(EventChannel = GetChannel( "Event" ))) - EventChannel = AddChannel( "Event", true, true ); + EventChannel = AddChannel( "Event", CH_ready ); + else + SetChannelInState( EventChannel, CH_ready ); // Load Polling configuration PollConfig = Config->GetChild( "Polling", true ); @@ -108,6 +110,13 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) ProcessName, Name, PersistFile ); } + // Event Output + StrVal = (char*)Config->GetChStr( "EventOutput", "None", true ); + EventOutputType = GetEventType( StrVal ); + + Log->Message( LogLevel, dlMedium, "%s/%s: Event Output - Type:%s", + ProcessName, Name, EventTypeName[EventOutputType] ); + // Update Devices -- may want to do it from derived class intead if (DeviceInit) { InitDevices( FunctionConfig ); @@ -235,15 +244,16 @@ bool CDeviceCore::CopyTemplateParam( TDevice * Device, TDeviceParam * Template, SetDataPath( Param, DataPath, DataNode ); } - if ((Template->DataType == dtUnsigned16) || (Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) { - UpdateUnsignedValue( Param, *((u_int16_t*)Template->Value), Template->Changed ); + if ((Template->DataType == dtBool) || (Template->DataType == dtUnsigned16) || + (Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) { + UpdateUnsignedValue( Param, *((u_int32_t*)Template->Value), Template->Changed ); if (Template->SetChanged) - SetUnsignedValue( Param, *((u_int16_t*)Template->Value), true ); + SetUnsignedValue( Param, *((u_int32_t*)Template->Value), true ); } else if ((Template->DataType == dtSigned16) || (Template->DataType == dtSigned32_HL) || (Template->DataType == dtSigned32_LH)) { - UpdateSignedValue( Param, *((int16_t*)Template->Value), Template->Changed ); + UpdateSignedValue( Param, *((int32_t*)Template->Value), Template->Changed ); if (Template->SetChanged) - SetSignedValue( Param, *((int16_t*)Template->Value), true ); + SetSignedValue( Param, *((int32_t*)Template->Value), true ); } else if ((Template->DataType == dtFloat32_L) || (Template->DataType == dtFloat32_B)) { UpdateFloatValue( Param, *((float*)Template->Value), Template->Changed ); @@ -381,7 +391,8 @@ bool CDeviceCore::InitDeviceParam( TDevice * Device, CDataMember * ParamConfig, SetDataPath( Param, DataPath, DataNode ); if ((InitVal = ParamConfig->GetChild( "InitValue", false ))) { - if ((DataType == dtUnsigned16) || (DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) { + if ((DataType == dtBool) || (DataType == dtUnsigned16) || + (DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) { UpdateUnsignedValue( Param, InitVal->GetInt(0), Read ); if (Write) SetUnsignedValue( Param, InitVal->GetInt(0), true ); @@ -432,6 +443,7 @@ bool CDeviceCore::SetPollParam( int pPollInterval ) bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries ) { + DefReplyTimeout = pReplyTimeout; ReplyTimeout = pReplyTimeout; MaxRetries = pMaxRetries; return true; @@ -456,12 +468,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; } @@ -673,6 +686,18 @@ TDeviceParam * CDeviceCore::AddDeviceParam( TDevice * Device, const char * Param // Init values switch (DataType) { + case dtBool : + // Create Value pointer + (*Param)->Value = (bool*)malloc( sizeof(bool) ); + *((bool*)(*Param)->Value) = 0; + (*Param)->Len = sizeof(bool); + + // Create Set Value pointer + (*Param)->SetValue = (bool*)malloc( sizeof(bool) ); + *((bool*)(*Param)->SetValue) = 0; + (*Param)->SetLen = sizeof(bool); + break; + case dtUnsigned16 : // Create Value pointer (*Param)->Value = (u_int16_t*)malloc( sizeof(u_int16_t) ); @@ -963,6 +988,25 @@ bool CDeviceCore::UpdateUnsignedValue( TDeviceParam * Param, const u_int32_t Val switch (Param->DataType) { + case dtBool : + if (Init || (*((bool*)Param->Value) != Value)) + { + // Set new value & mark change + *((bool*)Param->Value) = Value; + + if (Param->DataNode) + Param->DataNode->SetInt( *((bool*)Param->Value) ); + + // Mark change & log event + Changed = true; + if (Log) { + char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; + Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %u", ProcessName, Name, + ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) ); + } + } + break; + case dtUnsigned16 : if (Init || (*((u_int16_t*)Param->Value) != Value)) { @@ -1046,6 +1090,25 @@ bool CDeviceCore::UpdateSignedValue( TDeviceParam * Param, const int32_t Value, switch (Param->DataType) { + case dtBool : + if (Init || (*((bool*)Param->Value) != Value)) + { + // Set new value & mark change + *((bool*)Param->Value) = Value; + + if (Param->DataNode) + Param->DataNode->SetInt( *((bool*)Param->Value) ); + + // Mark change & log event + Changed = true; + if (Log) { + char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; + Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %d", ProcessName, Name, + ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) ); + } + } + break; + case dtSigned16 : if (Init || (*((int16_t*)Param->Value) != Value)) { @@ -1201,6 +1264,17 @@ bool CDeviceCore::SetUnsignedValue( TDeviceParam * Param, const u_int32_t Value, switch (Param->DataType) { + case dtBool : + if (Force || (*((bool*)Param->SetValue) != Value)) + { + // Set new value + *((bool*)Param->SetValue) = Value; + + // Mark change + Param->SetChanged = true; + } + break; + case dtUnsigned16 : if (Force || (*((u_int16_t*)Param->SetValue) != Value)) { @@ -1241,6 +1315,17 @@ bool CDeviceCore::SetSignedValue( TDeviceParam * Param, const int32_t Value, boo switch (Param->DataType) { + case dtBool : + if (Force || (*((bool*)Param->SetValue) != Value)) + { + // Set new value + *((bool*)Param->SetValue) = Value; + + // Mark change + Param->SetChanged = true; + } + break; + case dtSigned16 : if (Force || (*((int16_t*)Param->SetValue) != Value)) { @@ -1361,6 +1446,7 @@ bool CDeviceCore::SetValue( TDeviceParam * Param, const char * Value, const int // Convert to correct type switch (Param->DataType) { + case dtBool : case dtUnsigned16 : case dtUnsigned32_HL : case dtUnsigned32_LH : @@ -1405,6 +1491,10 @@ bool CDeviceCore::GetValue( TDeviceParam * Param, char * Value, int &Len ) // Check if return value longer than actual value switch (Param->DataType) { + case dtBool : + sprintf( Value, "%u", (*((bool*)Param->Value)) ); + break; + case dtUnsigned16 : sprintf( Value, "%u", (*((u_int16_t*)Param->Value)) ); break; @@ -1535,7 +1625,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]; @@ -1584,7 +1674,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) ); } } @@ -1593,7 +1683,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 )) @@ -1630,7 +1720,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 ); } } @@ -1639,7 +1729,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 )) @@ -1659,7 +1749,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 @@ -1667,7 +1757,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 @@ -1677,7 +1767,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; } @@ -1686,49 +1776,114 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons // Generate Event output bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) { + int EventLen = EventMsgLen; + CDataMember * Path = NULL; + // Validate if (!Param || !(Param->EventChannel)) return false; + if (EventOutputType == et_None) + return false; // Check Timer or force if (Force || (Param->EventInterval && Timeout( Param->EventTimeout, Param->EventInterval )) ) { + // Create message // Post event - char Message[200]; - switch (Param->DataType) - { - case dtUnsigned16 : - sprintf( Message, "%s: %u\n", Param->Name, *((u_int16_t*)Param->Value) ); - break; + if (true) { + // JSON output + EventData->Clear(); + EventData->SetChStr( "Type", "ParamEvent" ); + EventData->SetChStr( "Time", GetDateTimeStr() ); - case dtUnsigned32_HL : - case dtUnsigned32_LH : - sprintf( Message, "%s: %u\n", Param->Name, *((u_int32_t*)Param->Value) ); - break; + Path = EventData->GetChild( "Path", true ); + Path->SetArray(); + bool NewMember = true; + char * Start = NULL; + char * Pos = Param->DataPath; + while (true) { + if (!*Pos || (*Pos == '/')) { + NewMember = true; + if (Start) + Path->SetChStr( "[]", Start, Pos-Start ); + if (!*Pos) + break; + } + else if (NewMember) { + NewMember = false; + Start = Pos; + } + Pos++; + } + EventData->SetChStr( "Device", Param->Device->Name ); + EventData->SetChStr( "Param", Param->Name ); - case dtSigned16 : - sprintf( Message, "%s: %d\n", Param->Name, *((int16_t*)Param->Value) ); - break; + switch (Param->DataType) { + case dtBool : EventData->SetChBool( "Value", *((bool*)Param->Value) ); + break; - case dtSigned32_HL : - case dtSigned32_LH : - sprintf( Message, "%s: %d\n", Param->Name, *((int32_t*)Param->Value) ); - break; + case dtUnsigned16 : EventData->SetChBool( "Value", *((u_int16_t*)Param->Value) ); + break; - case dtFloat32_L : - case dtFloat32_B : - sprintf( Message, "%s: %f\n", Param->Name, *((float*)Param->Value) ); - break; + case dtUnsigned32_HL : + case dtUnsigned32_LH : EventData->SetChBool( "Value", *((u_int32_t*)Param->Value) ); + break; - case dtString : - sprintf( Message, "%s: %s\n", Param->Name, (char*)Param->Value ); - break; + case dtSigned16 : EventData->SetChBool( "Value", *((int16_t*)Param->Value) ); + break; - default : - break; + case dtSigned32_HL : + case dtSigned32_LH : EventData->SetChBool( "Value", *((int32_t*)Param->Value) ); + break; + + case dtFloat32_L : + case dtFloat32_B : EventData->SetChBool( "Value", *((float*)Param->Value) ); + break; + + case dtString : EventData->SetChBool( "Value", (char*)Param->Value ); + break; + + default : EventData->SetChNull( "Value" ); + break; + } + JSONparse->SetBase( EventData ); + JSONparse->WriteToString( NULL, EventMsg, EventLen, 0 ); } - Output( Param->EventChannel, Message, strlen(Message) ); + else { + switch (Param->DataType) + { + case dtBool : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((bool*)Param->Value) ); + break; + + case dtUnsigned16 : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int16_t*)Param->Value) ); + break; + + case dtUnsigned32_HL : + case dtUnsigned32_LH : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int32_t*)Param->Value) ); + break; + + case dtSigned16 : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int16_t*)Param->Value) ); + break; + + case dtSigned32_HL : + case dtSigned32_LH : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int32_t*)Param->Value) ); + break; + + case dtFloat32_L : + case dtFloat32_B : sprintf( EventMsg, "%s: %f\n", Param->DataPath, *((float*)Param->Value) ); + break; + + case dtString : sprintf( EventMsg, "%s: %s\n", Param->DataPath, (char*)Param->Value ); + break; + + default : sprintf( EventMsg, "%s:\n", Param->DataPath ); + break; + } + } + + // Send event + Output( Param->EventChannel, NULL, true, EventMsg, strlen(EventMsg) ); // Reset timer if (Param->EventInterval) { diff --git a/DeviceCore.h b/DeviceCore.h index 427243a..2cfb8cc 100644 --- a/DeviceCore.h +++ b/DeviceCore.h @@ -18,14 +18,16 @@ //--------------------------------------------------------------------------- // Enumerated types -typedef enum { dtNone = 0, dtUnsigned16 = 1, dtSigned16 = 2, dtUnsigned32_HL = 3, dtUnsigned32_LH = 4, - dtSigned32_HL = 5, dtSigned32_LH = 6, dtFloat32_L = 7, dtFloat32_B = 8, dtString = 9 } EDeviceDataType; - -// Constants +typedef enum { dtNone = 0, dtBool = 1, dtUnsigned16 = 2, dtSigned16 = 3, dtUnsigned32_HL = 4, dtUnsigned32_LH = 5, + dtSigned32_HL = 6, dtSigned32_LH = 7, dtFloat32_L = 8, dtFloat32_B = 9, dtString = 10 } EDeviceDataType; const char DataTypeCount = 10; -const char DataTypeName[][20] = { "None", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH", +const char DataTypeName[][20] = { "None", "Boolean", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH", "Signed32_HL", "Signed32_LH", "Float32_L", "Float32_B", "String" }; +typedef enum { et_None = 0, et_Simple = 1, et_JSON = 2 } EEventType; +const char EventTypeCount = 3; +const char EventTypeName[][10] = { "None", "Simple", "JSON" }; + //--------------------------------------------------------------------------- // Structure prototypes @@ -121,10 +123,10 @@ class CDeviceCore : public CFunctionCore { protected: // Configuration - CDataMember * ConfigTypes = NULL; - CDataMember * ValueTree = NULL; - CJSONparse * JSONparse = NULL; - bool DeviceInit = false; + CDataMember * ConfigTypes = NULL; + CDataMember * ValueTree = NULL; + CJSONparse * JSONparse = NULL; + bool DeviceInit = false; // Initialise device on start // Devices & Type TDevice * FirstDeviceType = NULL; @@ -132,24 +134,31 @@ 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 + + // Event output + EEventType EventOutputType = et_None; + CDataMember * EventData = NULL; + const int EventMsgLen = 1000; + char EventMsg[1000] = {0}; // Manage Devices bool DestroyDevice( TDevice ** Device ); @@ -231,11 +240,7 @@ protected: Param = &((*Param)->Next); return Param; } - inline TDeviceParamGroup * GetNextParamGroup( TDevice * Device, TDeviceParamGroup * LastParamGroup = NULL ) { - if (!Device) return NULL; - TDeviceParamGroup * ParamGroup = (LastParamGroup)? LastParamGroup->NextGroup : Device->FirstParamGroup; - return ParamGroup; - } + inline TDeviceParam * GetNextReadParam( TDevice * Device, TDeviceParam * LastParam = NULL ) { if (!Device) return NULL; TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam; @@ -275,6 +280,12 @@ protected: return Group; } + inline TDeviceParamGroup * GetNextParamGroup( TDevice * Device, TDeviceParamGroup * LastParamGroup = NULL ) { + if (!Device) return NULL; + TDeviceParamGroup * ParamGroup = (LastParamGroup)? LastParamGroup->NextGroup : Device->FirstParamGroup; + return ParamGroup; + } + // Find Param Groups Items inline TDeviceParamItem * GetParamItem( TDeviceParamGroup * Group, const char * ParamName ) { TDeviceParamItem ** Item = GetParamItemPtr( Group, ParamName ); @@ -295,6 +306,12 @@ protected: if (!strcasecmp( TypeName, DataTypeName[Type])) break; return (Type == DataTypeCount)? dtNone : (EDeviceDataType)Type; } + inline EEventType GetEventType( const char * TypeName ) { + int Type; + for (Type = 0; Type < EventTypeCount; Type++) + if (!strcasecmp( TypeName, EventTypeName[Type])) break; + return (Type == EventTypeCount)? et_None : (EEventType)Type; + } bool CompareParamString( const char * ParamValue, const int ParamLen, const char * Value, const int Len ); @@ -306,7 +323,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(); @@ -386,7 +403,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 a778ead..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; @@ -101,6 +84,9 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) if (!FunctionConfig ) return false; + // Set Type + FunctionConfig->SetChStr( "Type", Type ); + // Configure Logging/Debugging LogConfig = FunctionConfig->GetChild( "Log", true ); pLogLevel = Log->ReadLogLevel( LogConfig ); @@ -109,13 +95,8 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) // Load Channels ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); - while (ChannelConfig) - { - if (ChannelConfig->GetName()) { - AddChannel( ChannelConfig->GetName(), - ChannelConfig->GetChBool( "InputEnabled", true, true ), - ChannelConfig->GetChBool( "OutputEnabled", false, true )); - } + while (ChannelConfig) { + AddChannel( ChannelConfig->GetName(), CH_off ); ChannelConfig = ChannelConfig->GetNextPeer(); } @@ -124,7 +105,6 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); Config = Application->Config->GetChild( ConfigName, true ); } - if (Config->isNull()) Config->SetObject(); return true; } @@ -150,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(); } } @@ -181,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; @@ -203,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; @@ -371,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 11177af..c274f5c 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -17,6 +17,12 @@ //--------------------------------------------------------------------------- +// Enumarate Types +typedef enum { CH_off = 0, CH_standby = 1, CH_wait = 2, CH_ready = 3 } EChannelState; +const char ChannelStateName[][15] = { "Off", "Standby", "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; }; @@ -73,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; @@ -85,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 @@ -108,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..ef35ed0 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -8,6 +8,7 @@ // Standard C/C++ Libraries #include #include +#include // redA Libraries #include "JSONparseCore.h" @@ -145,7 +146,7 @@ bool CJSONparse::WriteToFile( const char * BasePath, const char * FilePath, cons // Open file if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC, 0660 )) < 0) { Error = true; - sprintf( ErrorText, "Could not open file" ); + sprintf( ErrorText, "Could not open file - [%d] %s", errno, strerror(errno) ); return false; } @@ -243,7 +244,7 @@ bool CJSONparse::ReadFromFile( const char * BasePath, const char * FilePath ) // Open file if ((Handle = open( FilePath, O_RDONLY )) < 0) { Error = true; - sprintf( ErrorText, "Could not open file" ); + sprintf( ErrorText, "Could not open file - [%d] %s", errno, strerror(errno) ); return false; } @@ -272,7 +273,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" ); @@ -351,11 +352,11 @@ bool CJSONparse::ReadFromBuffer( const char * BasePath ) // Parse Root Object SkipWhiteSpace(); - if (!ParseObject( BaseMember )) { + if (!ParseObject( BaseMember ) && !Error && !ParseArray( BaseMember )) { if (!Error) { Error = true; CharNo += BufPos-Mark; - sprintf( ErrorText, "First entry in file must be an Object on line %d:%d", LineNo, CharNo ); + sprintf( ErrorText, "First entry in file must be an Object or Array on line %d:%d", LineNo, CharNo ); } FreeBuffer(); return false; @@ -474,7 +475,7 @@ bool CJSONparse::ParseString( char ** Value, int &Len ) while (true) { // Check for special characters - if ((EndMark = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" ))) { + if ((EndMark = strpbrk( BufPos, "\"\\\n\t\b\f\n\r" ))) { /*"\"/\\\n\t\b\f\n\r" (forward slash included)*/ BufPos = EndMark; } else if (RefillBuffer) { FillBuffer(); @@ -690,7 +691,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 { @@ -815,7 +816,7 @@ bool CJSONparse::PrintString( char * String, int Len ) { // Scan for special chars Mark = BufPos; - while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && (*BufPos != '/') && (*BufPos != '"')) + while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && /*(*BufPos != '/') &&*/ (*BufPos != '"')) BufPos++; // Print Portion @@ -1028,9 +1029,7 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent ) break; case jtString : - if ((Print( this, "\"", 1 ) < 0) || - (Print( this, Member->Value, Member->Len ) < 0) || - (Print( this, "\"", 1 ) < 0)) + if (!PrintString( Member->Value, Member->Len )) return false; break; 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..07e3994 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,41 @@ 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; - } + // Execute call back for state + 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 if (Handle->AutoManage) + ChannelState = CH_standby; + else + ChannelState = CH_off; + if (Handle->Channel->InState != ChannelState) + SetChannelInState( Handle->Channel, ChannelState ); + } return true; } //--------------------------------------------------------------------------- @@ -322,9 +300,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 +320,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 +333,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 +373,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 +393,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 +414,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 +515,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 +659,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 +675,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_off) { // 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 off", + 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 +706,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 +733,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 +814,25 @@ 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 ); } } + else if (Handle->Channel && (Handle->Channel->InState == CH_off) && Handle->AutoManage) { + // Set channel to standby + SetChannelInState( Handle->Channel, CH_standby ); + } // Check Input buffers - if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) - { + 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 +842,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..814f2e5 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,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) short Parity; short FlowCtrl; short Queue; - long Delay; + bool Persitent; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) @@ -138,6 +171,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) SerialConfig->GetChInt( "DataBits", 8, true ), Parity, SerialConfig->GetChInt( "StopBits", 1, true ), FlowCtrl, SerialConfig->GetChInt( "DataWait", 0, true )); + Persitent = true; } } else if (!strcasecmp( Type, "LinePrinter" )) @@ -148,6 +182,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Port/Address", NULL, true ); // Get default value } SetLinePrinterHandle( Handle, Address ); + Persitent = true; } else if (!strcasecmp( Type, "UNIXserver" )) { @@ -158,6 +193,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) } Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true ); SetUnixHandle( Handle, ctUNIXserver, Address, Queue ); + Persitent = true; } else if (!strcasecmp( Type, "UNIXclient" )) { @@ -167,73 +203,75 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value } SetUnixHandle( Handle, ctUNIXclient, Address, 0 ); + Persitent = false; } else if (!strcasecmp( Type, "UDPserver" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); - SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0, Delay ); + SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0 ); + Persitent = true; } else if (!strcasecmp( Type, "UDPclient" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); - SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0, Delay ); + SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0 ); + Persitent = false; } else if (!strcasecmp( Type, "TCPserver" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - 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 ); + Persitent = true; } else if (!strcasecmp( Type, "TCPclient" )) { if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = GetHandleAddress( Handle, Name ))) { Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value - Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value + Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value } else { Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value - Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value + Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value } - Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); - SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0, Delay ); + SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0 ); + Persitent = false; } else if (!strcasecmp( Type, "ForkPipe" )) { Address = (char*)HandleConfig->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value SetForkPipeHandle( Handle, Address ); + Persitent = true; } // Set Auto Manage - SetAutoManage( Handle, HandleConfig->GetChBool( "AutoManage/Enabled", true, true ), - HandleConfig->GetChBool( "AutoManage/Persistent", false, true ), - HandleConfig->GetChInt( "AutoManage/ReopenDelay", 2000, true ), - HandleConfig->GetChInt( "AutoManage/CloseTimeout", 2000, true )); + SetAutoManage( Handle, HandleConfig->GetChBool( "AutoManage/Enabled", true, true ), + HandleConfig->GetChBool( "AutoManage/Persistent", Persitent, true ), + HandleConfig->GetChInt( "AutoManage/ReopenDelay", 2000, true ), + HandleConfig->GetChInt( "AutoManage/CloseTimeout", 2000, true )); // Input buffer - SetInBuffer( Handle, HandleConfig->GetChInt( "InputBuffer/Size", 0 ), - HandleConfig->GetChInt( "InputBuffer/Timeout", 250 ), - HandleConfig->GetChStr( "InputBuffer/Marker", "" ), - HandleConfig->GetChInt( "InputBuffer/MarkerLen", 0 ) ); - SetOutBuffer( Handle, HandleConfig->GetChInt( "OutputBuffer/Size", 0 ) ); + SetInBuffer( Handle, HandleConfig->GetChInt( "InputBuffer/Size", 0 ), + HandleConfig->GetChInt( "InputBuffer/Timeout", 250 ), + HandleConfig->GetChStr( "InputBuffer/Marker", "" ), + HandleConfig->GetChInt( "InputBuffer/MarkerLen", 0 ) ); + SetOutBuffer( Handle, HandleConfig->GetChInt( "OutputBuffer/Size", 0 ) ); // Next HandleConfig = HandleConfig->GetNextPeer(); @@ -243,6 +281,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 +472,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 +483,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 +561,7 @@ THandle * CSelectableCore::OpenSerialPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -486,7 +604,7 @@ THandle * CSelectableCore::OpenLinePrinterPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -588,7 +706,7 @@ THandle * CSelectableCore::OpenForkPipe( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -612,7 +730,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 +742,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 +766,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) // Set state close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return NULL; }; @@ -662,7 +781,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) // Set state close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return NULL; }; @@ -676,7 +796,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -702,7 +822,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 +849,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -745,11 +865,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 +883,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -861,7 +980,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -869,14 +988,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 +1031,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 +1141,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 +1157,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 +1168,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 +1183,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 +1203,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1042,7 +1233,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 +1265,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 +1274,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 +1285,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 +1302,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 +1326,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 +1337,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 +1350,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 +1365,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 +1380,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 +1396,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 +1415,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1270,7 +1463,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 +1472,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 +1517,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->HostName ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -1333,13 +1525,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 +1543,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 +1554,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 +1566,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 +1594,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 +1609,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -1430,17 +1625,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 +1661,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 +1726,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 +1819,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 +1876,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 +2038,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 +2052,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 +2203,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; } @@ -2144,53 +2340,6 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len } //--------------------------------------------------------------------------- -bool CSelectableCore::Process() -{ - THandle * Handle = NULL; - - // Process all Handles - Handle = FirstHandle; - while (Handle) - { - // Auto manage handles - if ((Handle->State == csOpenRequest)) { - // Resolve then open socket - if (Timeout( Handle->LastAction, Handle->ResolveDelay )) { - Open( Handle, false ); - } - } - 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 ); - } - } - - // Check Input buffers - if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) { - // Check duration since last PortIn - if (Timeout( Handle->InStart, Handle->InTimeout )) { - // Process Input - ProcessInputBuffer( Handle, true ); - - // Reset timer - ClearStartTime( &(Handle->InStart) ); - } - } - - // Check for auto close (but not on servers) - if ((Handle->State == csOpen) && Handle->AutoManage && !Handle->Persistent && (Handle->Type != ctTCPserver) && (Handle->Type != ctUNIXserver)) { - // Close port after timeout - if (Timeout( Handle->LastAction, Handle->CloseTimeout )) { - Close( Handle, true ); - } - } - Handle = Handle->Next; - } - return true; -} -//--------------------------------------------------------------------------- - // Set serial port configuration parameters bool CSelectableCore::WriteSerialConfig( THandle * Handle ) { @@ -2471,3 +2620,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..67a8207 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,25 @@ 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 bool Process(); + virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); + + 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; iGetChInt( "Parameters/PingInterval", 500, true )); + SetInterval( Config->GetChInt( "PingInterval", 500, true )); // Create handle and set reference, if not done if (!(Ping = GetHandle( "Ping" )))