Merge branch 'master' into ModbusCore

This commit is contained in:
Charl Wentzel
2019-07-10 19:50:26 +02:00
21 changed files with 1110 additions and 972 deletions

View File

@@ -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;
}
}

View File

@@ -131,10 +131,8 @@ CDataMember * CDataMember::CreateChild( const char * Name, const int Len )
bool CDataMember::Clear()
{
// Clear value
if (Value) {
if (Value)
free( Value );
Value = NULL;
}
// Clear children
while (FirstChild) {
@@ -142,7 +140,9 @@ bool CDataMember::Clear()
}
// Reset value
Type = jtNull;
Type = jtNull;
Value = NULL;
Len = 0;
return true;
}
//---------------------------------------------------------------------------

View File

@@ -20,24 +20,24 @@ static char ReturnStr[30];
//---------------------------------------------------------------------------
// Set current time on real-time clock
bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds )
{
struct tm NewTime;
struct timeval tv;
struct timezone tz;
// Get current date and time
// Get current Epoch (UTC)
gettimeofday( &tv, &tz);
// Change to new time
// Convert to local time
localtime_r( &tv.tv_sec, &NewTime );
// Set new time (keep date as is)
NewTime.tm_hour = Hours;
NewTime.tm_min = Minutes;
NewTime.tm_sec = Seconds;
// Convert back
// Convert back from local time to epoch time
tv.tv_sec = mktime( &NewTime );
tv.tv_usec = 0;
@@ -47,43 +47,24 @@ bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds
}
//---------------------------------------------------------------------------
// Get current time from real-time clock
bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
time_t UTC;
// Get current date and time
time( &UTC );
localtime_r( &UTC, &CurrentTime );
// Extract time
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
return true;
}
//---------------------------------------------------------------------------
// Set current date on real-time clock
bool SetDate( unsigned char Day, unsigned char Month, unsigned Year )
{
struct tm NewDate;
struct timeval tv;
struct timezone tz;
// Get current date and time
// Get current Epoch (UTC)
gettimeofday( &tv, &tz );
// Change to new time
// Convert to local time
localtime_r( &tv.tv_sec, &NewDate );
// Set new date (keep time as is)
NewDate.tm_year = Year - 1900;
NewDate.tm_mon = Month - 1;
NewDate.tm_mday = Day;
// Convert back
// Convert back from local time to epoch time
tv.tv_sec = mktime( &NewDate );
tv.tv_usec = 0;
@@ -94,17 +75,70 @@ bool SetDate( unsigned char Day, unsigned char Month, unsigned Year )
}
//---------------------------------------------------------------------------
// Get current data from real-time clock
bool SetDateTime( unsigned char Day, unsigned char Month, unsigned Year,
unsigned char Hours, unsigned char Minutes, unsigned char Seconds )
{
struct tm NewTime;
struct timeval tv;
struct timezone tz;
// Get current Epoch (UTC)
gettimeofday( &tv, &tz);
// Convert to local time
localtime_r( &tv.tv_sec, &NewTime );
// Set new date & time
NewTime.tm_year = Year - 1900;
NewTime.tm_mon = Month - 1;
NewTime.tm_mday = Day;
NewTime.tm_hour = Hours;
NewTime.tm_min = Minutes;
NewTime.tm_sec = Seconds;
// Convert back from local time to epoch time
tv.tv_sec = mktime( &NewTime );
tv.tv_usec = 0;
// Set date and new time
settimeofday( &tv, &tz);
return true;
}
//---------------------------------------------------------------------------
bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
time_t UTC;
// Get current UTC date and time
time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentTime );
// Extract time only
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
return true;
}
//---------------------------------------------------------------------------
bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year )
{
struct tm CurrentDate;
time_t UTC;
// Get current date and time
// Get current UTC date and time
time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentDate );
// Extract date
// Extract date only
Day = CurrentDate.tm_mday;
Month = CurrentDate.tm_mon + 1;
Year = CurrentDate.tm_year + 1900;
@@ -113,7 +147,31 @@ bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year )
}
//---------------------------------------------------------------------------
// Get the current date in a string
bool GetDateTime( unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
time_t UTC;
// Get current UTC date and time
time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentTime );
// Extract Date & time
Day = CurrentTime.tm_mday;
Month = CurrentTime.tm_mon + 1;
Year = CurrentTime.tm_year + 1900;
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
return true;
}
//---------------------------------------------------------------------------
char const * GetDateStr( const char * DateSeparator )
{
unsigned char Day;
@@ -172,12 +230,15 @@ char const * GetDateTimeStr( const char * DateSeparator, const char * TimeSepar
//---------------------------------------------------------------------------
// Get current time from real-time clock
bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
bool ReadTime( const time_t EpochTime, bool LocalTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
// Get current date and time
localtime_r( &EpochTime, &CurrentTime );
if (LocalTime)
localtime_r( &EpochTime, &CurrentTime );
else
gmtime_r( &EpochTime, &CurrentTime );
// Extract time
Hours = CurrentTime.tm_hour;
@@ -188,12 +249,15 @@ bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minu
}
//---------------------------------------------------------------------------
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year )
bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year )
{
struct tm CurrentDate;
// Get current date and time
localtime_r( &EpochTime, &CurrentDate );
if (LocalTime)
localtime_r( &EpochTime, &CurrentDate );
else
gmtime_r( &EpochTime, &CurrentDate );
// Extract date
Day = CurrentDate.tm_mday;
@@ -204,15 +268,118 @@ bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month,
}
//---------------------------------------------------------------------------
bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
// Get current date and time
if (LocalTime)
localtime_r( &EpochTime, &CurrentTime );
else
gmtime_r( &EpochTime, &CurrentTime );
// Extract time
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
// Extract date
Day = CurrentTime.tm_mday;
Month = CurrentTime.tm_mon + 1;
Year = CurrentTime.tm_year + 1900;
return true;
}
//---------------------------------------------------------------------------
// Read components from date/time string
bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime )
{
int ItemsAssigned;
int TempDay;
int TempMonth;
int TempYear;
int TempHours = -1;
int TempMinutes = -1;
int TempSeconds = -1;
// Read string
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds );
// Return Values
Hours = (TempHours != -1)? TempHours : (Maxtime)? 23 : 0;
Minutes = (TempMinutes != -1)? TempMinutes : (Maxtime)? 59 : 0;
Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0;
// Check if success
return ((ItemsAssigned >= 3)? true : false);
}
//---------------------------------------------------------------------------
bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year )
{
int ItemsAssigned;
int TempDay;
int TempMonth;
int TempYear;
int TempHours = -1;
int TempMinutes = -1;
int TempSeconds = -1;
// Read string
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds );
// Return Values
Day = TempDay;
Month = TempMonth;
Year = TempYear;
// Check if success
return ((ItemsAssigned >= 3)? true : false);
}
//---------------------------------------------------------------------------
bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime )
{
int ItemsAssigned;
int TempDay;
int TempMonth;
int TempYear;
int TempHours = -1;
int TempMinutes = -1;
int TempSeconds = -1;
// Read string
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds );
// Return Values
Day = TempDay;
Month = TempMonth;
Year = TempYear;
Hours = (TempHours != -1)? TempHours : (Maxtime)? 23 : 0;
Minutes = (TempMinutes != -1)? TempMinutes : (Maxtime)? 59 : 0;
Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0;
// Check if success
return ((ItemsAssigned >= 3)? true : false);
}
//---------------------------------------------------------------------------
// Get the current date in a string
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator )
char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator )
{
unsigned char Day;
unsigned char Month;
unsigned int Year;
// Get Date
ReadDate( EpochTime, Day, Month, Year );
ReadDate( EpochTime, LocalTime, Day, Month, Year );
// Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d",
@@ -223,14 +390,14 @@ char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator )
}
//---------------------------------------------------------------------------
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator )
char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator )
{
unsigned char Hours;
unsigned char Minutes;
unsigned char Seconds;
// Get Date & Time
ReadTime( EpochTime, Hours, Minutes, Seconds );
ReadTime( EpochTime, LocalTime, Hours, Minutes, Seconds );
// Build String
sprintf( ReturnStr, "%02d%s%02d%s%02d",
@@ -240,7 +407,7 @@ char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator )
}
//---------------------------------------------------------------------------
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator, const char * TimeSeparator )
char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator, const char * TimeSeparator )
{
unsigned char Day;
unsigned char Month;
@@ -250,8 +417,7 @@ char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparato
unsigned char Seconds;
// Get Date & Time
ReadDate( EpochTime, Day, Month, Year );
ReadTime( EpochTime, Hours, Minutes, Seconds );
ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds );
// Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d",

View File

@@ -17,11 +17,15 @@
//---------------------------------------------------------------------------
// Get and set System Date and Time
bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds );
bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool SetDate( unsigned char Day, unsigned char Month, unsigned Year );
bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year );
bool GetDateTime( unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds );
bool SetDate( unsigned char Day, unsigned char Month, unsigned Year );
bool SetDateTime( unsigned char Day, unsigned char Month, unsigned Year,
unsigned char Hours, unsigned char Minutes, unsigned char Seconds );
char const * GetDateStr( const char * DateSeparator = "/" );
char const * GetTimeStr( const char * TimeSeparator = ":" );
@@ -29,12 +33,20 @@ char const * GetDateTimeStr( const char * DateSeparator = "/", const char * Tim
//---------------------------------------------------------------------------
bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year );
// Build or interpret time data
bool ReadTime( const time_t EpochTime, bool LocalTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year );
bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator = "/" );
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator = ":" );
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" );
bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime );
bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year );
bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime );
char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/" );
char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator = ":" );
char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" );
//---------------------------------------------------------------------------

View File

@@ -18,7 +18,7 @@
// Global Vars
extern char * ProcessName;
extern CApplication * Application;
//extern CApplication * Application;
//---------------------------------------------------------------------------
@@ -30,20 +30,9 @@ extern CApplication * Application;
CDeviceCore::CDeviceCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
{
// Polling
PollCycle = 0;
PollStep = 0;
PollInterval = 250;
SetStartTime( &PollWait );
WaitingForReply = false;
ReplyTimeout = 200;
InvalidReply = false;
PollRetry = 0;
MaxRetries = 3;
// Data Structures
DeviceInit = true;
ConfigTypes = new CDataMember();
ValueTree = new CDataMember();
JSONparse = new CJSONparse();
@@ -69,7 +58,6 @@ CDeviceCore::~CDeviceCore()
bool CDeviceCore::Init( CDataMember * FunctionConfig )
{
char * PersistFile = NULL;
char * ConfigName = NULL;
CDataMember * PollConfig = NULL;
int IntVal1;
int IntVal2;
@@ -80,18 +68,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig )
// Add Channels
if (!(CmdChannel = GetChannel( "Command" )))
CmdChannel = AddChannel( "Command", true, true );
if (!(DeviceChannel = GetChannel( "Device" )))
DeviceChannel = AddChannel( "Device", true, true );
if (!(EventChannel = GetChannel( "Event" )))
EventChannel = AddChannel( "Event", true, true );
CmdChannel = AddChannel( "Command", CH_ready );
else
SetChannelInState( CmdChannel, CH_ready );
// Get configuration
if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) {
ConfigName = (char*)FunctionConfig->GetChStr( "Config" );
Config = Application->Config->GetChild( ConfigName, true );
}
if (Config->isNull()) Config->SetObject();
if (!(DeviceChannel = GetChannel( "Device" )))
DeviceChannel = AddChannel( "Device", CH_ready );
else
SetChannelInState( DeviceChannel, CH_ready );
if (!(EventChannel = GetChannel( "Event" )))
EventChannel = AddChannel( "Event", CH_ready );
else
SetChannelInState( EventChannel, CH_ready );
// Load Polling configuration
PollConfig = Config->GetChild( "Polling", true );
@@ -442,6 +431,7 @@ bool CDeviceCore::SetPollParam( int pPollInterval )
bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries )
{
DefReplyTimeout = pReplyTimeout;
ReplyTimeout = pReplyTimeout;
MaxRetries = pMaxRetries;
return true;
@@ -466,12 +456,13 @@ bool CDeviceCore::DeviceOnline( TDevice * Device, bool Online )
}
//---------------------------------------------------------------------------
void CDeviceCore::SetWaitForReply()
void CDeviceCore::SetWaitForReply( int CustomTimeout )
{
// Start timer
SetStartTime( &PollWait );
// Set flag
ReplyTimeout = (CustomTimeout >= 0)? CustomTimeout : DefReplyTimeout;
WaitingForReply = true;
InvalidReply = false;
}
@@ -1622,7 +1613,7 @@ bool CDeviceCore::GetCmdParam( const char * Start, char * Param, char ** NextPar
}
//---------------------------------------------------------------------------
int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, const int MaxLen )
int CDeviceCore::HandleCommand( const char *ChannelName, const char * SourceRef, const char * Data, const int MaxLen )
{
int Len;
char Value[50];
@@ -1671,7 +1662,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
}
else {
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
@@ -1680,7 +1671,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Get",
ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
else if (!strcasecmp( "set", Value ))
@@ -1717,7 +1708,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
}
else {
sprintf( OutputStr, "> set %s,%s = %s\n", Device->Name, Param->Name, Value );
Output( ChannelName, OutputStr );
Output( ChannelName, NULL, true, OutputStr );
}
}
@@ -1726,7 +1717,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Set",
ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
else if (!strcasecmp( "status", Value ))
@@ -1746,7 +1737,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
}
else {
sprintf( OutputStr, "> %s - %s\n", Device->Name, ((Device->Online)? "online" : "offline") );
Output( ChannelName, OutputStr );
Output( ChannelName, NULL, true, OutputStr );
}
// Report error
@@ -1754,7 +1745,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Status",
ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
else
@@ -1764,7 +1755,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s', %s%s",
ProcessName, Name, ChannelName, Value, OutputStr );
strcat( OutputStr, " (comma separated values)\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
return MaxLen;
}
@@ -1819,7 +1810,7 @@ bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force )
default :
break;
}
Output( Param->EventChannel, Message, strlen(Message) );
Output( Param->EventChannel, NULL, true, Message, strlen(Message) );
// Reset timer
if (Param->EventInterval) {

View File

@@ -121,11 +121,10 @@ class CDeviceCore : public CFunctionCore
{
protected:
// Configuration
CDataMember * Config = NULL;
CDataMember * ConfigTypes = NULL;
CDataMember * ValueTree = NULL;
CJSONparse * JSONparse = NULL;
bool DeviceInit = false;
CDataMember * ConfigTypes = NULL;
CDataMember * ValueTree = NULL;
CJSONparse * JSONparse = NULL;
bool DeviceInit = false; // Initialise device on start
// Devices & Type
TDevice * FirstDeviceType = NULL;
@@ -133,24 +132,25 @@ protected:
TDevice * ActiveDevice = NULL;
// Standard channels
TChannel * DeviceChannel = NULL;
TChannel * CmdChannel = NULL;
TChannel * EventChannel = NULL;
TChannel * DeviceChannel = NULL;
TChannel * CmdChannel = NULL;
TChannel * EventChannel = NULL;
// Poll
int PollCycle; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown
int PollStep; // Position in polling sequence
timeval PollWait; // Time at which last poll was done
long PollInterval; // Minimum delay between polls
int PollCycle = 0; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown
int PollStep = 0; // Position in polling sequence
timeval PollWait = {0,0}; // Time at which last poll was done
long PollInterval = 250; // Minimum delay between polls
// Reply
bool WaitingForReply; // Command sent, waiting for reply
bool InvalidReply; // Invalid reply received
long ReplyTimeout; // Max waiting time for reply
bool WaitingForReply = false; // Command sent, waiting for reply
bool InvalidReply = false; // Invalid reply received
long DefReplyTimeout = 500; // Default Max waiting time for reply
long ReplyTimeout = 500; // Max waiting time for reply
// Retry
int PollRetry; // No of polling retries that has timed out
int MaxRetries; // Max allowed retries
int PollRetry = 0; // No of polling retries that has timed out
int MaxRetries = 3; // Max allowed retries
// Manage Devices
bool DestroyDevice( TDevice ** Device );
@@ -309,7 +309,7 @@ protected:
virtual bool DeviceOnline( TDevice * Device, bool Online );
// Handle Reply Timing
virtual void SetWaitForReply();
virtual void SetWaitForReply( int CustomTimeout = -1 );
virtual void ValidReplyReceived();
virtual bool CheckReplyTimeout();
@@ -389,7 +389,7 @@ public:
// Handle Interface Commands
bool GetCmdParam( const char * Start, char * Param, char ** NextParam );
int HandleCommand( const char *ChannelName, const char * Data, const int MaxLen );
int HandleCommand( const char *ChannelName, const char * SourceRef, const char * Data, const int MaxLen );
// Command Text Interfaces
bool SetValue( TDeviceParam * Param, const char * Value, const int Len, bool Force );

View File

@@ -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;

View File

@@ -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();

View File

@@ -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_ */

View File

@@ -30,9 +30,8 @@ extern CApplication * Application;
CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( pType )
{
// Set name
if (pName) {
if (pName)
Name = strdup( pName );
}
// Logging
Log = Application->Log;
@@ -44,35 +43,19 @@ CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( p
CFunctionCore::~CFunctionCore()
{
TChannel * NextChannel = NULL;
TChannelLink * NextLinkedChannel = NULL;
// Destroy Channels
while (FirstChannel)
{
// Destroy Linked Channels
while (FirstChannel->FirstLink)
UnlinkChannel( FirstChannel->Name, FirstChannel->FirstLink->Function->Name, FirstChannel->FirstLink->Channel->Name );
// Destroy Parameters
if (FirstChannel->Name) {
if (FirstChannel->Name)
free( FirstChannel->Name );
}
// Destroy Linked Inputs
while (FirstChannel->FirstInput) {
if (FirstChannel->FirstInput->Name) {
free( FirstChannel->FirstInput->Name );
}
NextLinkedChannel = FirstChannel->FirstInput->Next;
delete FirstChannel->FirstInput;
FirstChannel->FirstInput = NextLinkedChannel;
}
// Destroy Linked Outputs
while (FirstChannel->FirstOutput) {
if (FirstChannel->FirstOutput->Name) {
free( FirstChannel->FirstOutput->Name );
}
NextLinkedChannel = FirstChannel->FirstOutput->Next;
delete FirstChannel->FirstOutput;
FirstChannel->FirstOutput = NextLinkedChannel;
}
if (FirstChannel->Ref)
free( FirstChannel->Ref );
// Destroy Channel
NextChannel = FirstChannel->Next;
@@ -95,11 +78,15 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
CDataMember * ChannelConfig;
EDebugLevel pLogLevel;
int pLogOutput;
char * ConfigName = NULL;
// Validate
if (!FunctionConfig )
return false;
// Set Type
FunctionConfig->SetChStr( "Type", Type );
// Configure Logging/Debugging
LogConfig = FunctionConfig->GetChild( "Log", true );
pLogLevel = Log->ReadLogLevel( LogConfig );
@@ -108,16 +95,17 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
// Load Channels
ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true );
while (ChannelConfig)
{
if (ChannelConfig->GetName()) {
AddChannel( ChannelConfig->GetName(),
ChannelConfig->GetChBool( "InputEnabled", true, true ),
ChannelConfig->GetChBool( "OutputEnabled", false, true ));
}
while (ChannelConfig) {
AddChannel( ChannelConfig->GetName(), CH_off );
ChannelConfig = ChannelConfig->GetNextPeer();
}
// Get main configuration
if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) {
ConfigName = (char*)FunctionConfig->GetChStr( "Config" );
Config = Application->Config->GetChild( ConfigName, true );
}
return true;
}
//---------------------------------------------------------------------------
@@ -142,10 +130,11 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig )
while (FunctionMember)
{
// Get Parameters
LinkOutputChannel( Channel->Name,
FunctionMember->GetChStr( "Function" ),
FunctionMember->GetChStr( "Channel" ),
FunctionMember->GetChBool( "Bidirectional" ) );
LinkChannel( Channel->Name,
FunctionMember->GetChStr( "Function", NULL, true ),
FunctionMember->GetChStr( "Channel", NULL, true ),
FunctionMember->GetChBool( "Input", false, true ),
FunctionMember->GetChBool( "Output", false, true ) );
FunctionMember = FunctionMember->GetNextPeer();
}
}
@@ -173,7 +162,7 @@ bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel )
}
//---------------------------------------------------------------------------
TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInputEnable, const bool pOutputEnable )
TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelState State )
{
TChannel ** Channel = NULL;
@@ -195,166 +184,263 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu
// Set Name
(*Channel)->Name = strdup( ChannelName );
(*Channel)->Ref = (char*)malloc( strlen(Name)+strlen(ChannelName)+2 );
sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName );
(*Channel)->InState = State;
(*Channel)->OutState = CH_off;
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', In:%s, Out:%s",
ProcessName, Name, ChannelName, (*Channel)->Ref,
ChannelStateName[(*Channel)->InState], ChannelStateName[(*Channel)->OutState]);
}
// Set parameters
(*Channel)->InputEnabled = pInputEnable;
(*Channel)->OutputEnabled = pOutputEnable;
return *Channel;
}
//---------------------------------------------------------------------------
// Automated Data Input/Output
bool CFunctionCore::LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional )
bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State )
{
CFunctionCore * OutFunction = NULL;
TChannel * Channel = NULL;
TChannelLink ** LinkedChannel = NULL;
EChannelState OldState = Channel->InState;
TChannelLink * LinkChannel;
// Get Channel
if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) {
// Validate
if (!Channel)
return false;
}
// Check if linked Channel exists
LinkedChannel = &(Channel->FirstInput);
while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) {
LinkedChannel = &((*LinkedChannel)->Next);
}
// Update state
Channel->InState = State;
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s",
ProcessName, Name, Channel->Ref, ChannelStateName[State] );
// Create if not found
if (!*LinkedChannel)
{
// Create
*LinkedChannel = new TChannelLink;
// Update linked channels
LinkChannel = Channel->FirstLink;
while (LinkChannel) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s",
ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] );
// Set Parameters
(*LinkedChannel)->Function = OutFunction;
(*LinkedChannel)->Name = strdup( OutChannelName );
// Trigger Linked Channel Events
LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel );
LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State );
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Input Linked - '%s'/'%s' <-- '%s'/'%s'",
ProcessName, Name, Name, ChannelName, OutFunction->GetName(), OutChannelName );
}
// Link Return direction as well
if (Bidirectional) {
return OutFunction->LinkInputChannel( OutChannelName, Name, ChannelName, false );
LinkChannel = LinkChannel->Next;
}
return true;
}
//---------------------------------------------------------------------------
bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional )
bool CFunctionCore::UpdateChannelOutState( TChannel * Channel )
{
TChannel * OutChannel = NULL;
CFunctionCore * InFunction = NULL;
TChannel * InChannel = NULL;
TChannelLink * LinkChannel;
EChannelState OutState;
// Check if channel Out state changed
OutState = CH_off;
LinkChannel = Channel->FirstLink;
while (LinkChannel) {
if (LinkChannel->Channel->InState > OutState)
OutState = LinkChannel->Channel->InState;
LinkChannel = LinkChannel->Next;
}
if (OutState != Channel->OutState) {
// Update output state
Channel->OutState = OutState;
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - Out:%s",
ProcessName, Name, Channel->Ref, ChannelStateName[OutState] );
}
return true;
}
//---------------------------------------------------------------------------
EChannelState CFunctionCore::GetChannelOutState( TChannel * Channel, const char * TargetRef )
{
TChannelLink * LinkChannel = NULL;
// Validate
if (!Channel) {
return CH_off;
}
else if (!TargetRef || !*TargetRef) {
return Channel->OutState;
}
else if ((LinkChannel = GetLinkChannel( Channel, TargetRef ))) {
return LinkChannel->Channel->InState;
}
else {
return CH_off;
}
}
//---------------------------------------------------------------------------
// Automated Data Input/Output
bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output )
{
TChannel * Channel = NULL;
CFunctionCore * LinkFunction = NULL;
TChannel * LinkChannel = NULL;
TChannelLink ** LinkedChannel = NULL;
// Check if Channels & Function exist
if (!(OutChannel = GetChannel( ChannelName )) ||
!(InFunction = Application->GetFunction( InFunctionName )) ||
!(InChannel = InFunction->GetChannel( InChannelName )) ) {
if (!(Channel = GetChannel( ChannelName )) ||
!(LinkFunction = Application->GetFunction( LinkFunctionName )) ||
!(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) {
return false;
}
// Check if linked Channel exists
LinkedChannel = &(OutChannel->FirstOutput);
while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) {
LinkedChannel = &(Channel->FirstLink);
while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel))
LinkedChannel = &((*LinkedChannel)->Next);
}
// Create if not found
if (!*LinkedChannel)
{
// Create
*LinkedChannel = new TChannelLink;
// Set Parameters
(*LinkedChannel)->Function = InFunction;
(*LinkedChannel)->Name = strdup( InChannelName );
// Set Parameters
(*LinkedChannel)->Function = LinkFunction;
(*LinkedChannel)->Channel = LinkChannel;
(*LinkedChannel)->Input = Input;
(*LinkedChannel)->Output = Output;
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s'/'%s' --> '%s'/'%s'",
ProcessName, Name, Name, ChannelName, InFunction->GetName(), InChannelName );
}
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Linked - '%s'-->'%s' - In:%s, Out:%s",
ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref, ((Input)? "Yes" : "No"), ((Output)? "Yes" : "No") );
// Link return direction as well
if (Bidirectional) {
return InFunction->LinkOutputChannel( InChannelName, Name, ChannelName, false );
}
// Find Linked channel on remote function
LinkedChannel = &(LinkChannel->FirstLink);
while (*LinkedChannel && ((*LinkedChannel)->Channel != Channel))
LinkedChannel = &((*LinkedChannel)->Next);
if (!*LinkedChannel)
*LinkedChannel = new TChannelLink;
// Set Parameters
(*LinkedChannel)->Function = this;
(*LinkedChannel)->Channel = Channel;
(*LinkedChannel)->Input = Output;
(*LinkedChannel)->Output = Input;
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Linked - '%s'-->'%s' - In:%s, Out:%s",
ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref, ((Output)? "Yes" : "No"), ((Input)? "Yes" : "No") );
// Trigger Forward Channel Events
LinkFunction->UpdateChannelOutState( LinkChannel );
LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState );
// Trigger Reverse Channel Events
UpdateChannelOutState( Channel );
ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState );
return true;
}
//---------------------------------------------------------------------------
// Manual Data Input/Output
int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len )
bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName )
{
TChannel * Channel = NULL;
TChannel * Channel = NULL;
CFunctionCore * LinkFunction = NULL;
TChannel * LinkChannel = NULL;
TChannelLink ** LinkedChannel = NULL;
TChannelLink * NextLinkedChannel = NULL;
// Check if Channels & Function exist
if (!(Channel = GetChannel( ChannelName )) ||
!(LinkFunction = Application->GetFunction( LinkFunctionName )) ||
!(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) {
return false;
}
// Check if linked Channel exists
LinkedChannel = &(Channel->FirstLink);
while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel))
LinkedChannel = &((*LinkedChannel)->Next);
// Unlink channel
if (*LinkedChannel) {
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Unlinked - '%s'-x->'%s'",
ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref );
NextLinkedChannel = (*LinkedChannel)->Next;
delete *LinkedChannel;
*LinkedChannel = NextLinkedChannel;
}
// Find Linked channel on remote function
LinkedChannel = &(LinkChannel->FirstLink);
while (*LinkedChannel && ((*LinkedChannel)->Channel != Channel))
LinkedChannel = &((*LinkedChannel)->Next);
// Unlink channel
if (*LinkedChannel) {
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Unlinked - '%s'-x->'%s'",
ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref );
NextLinkedChannel = (*LinkedChannel)->Next;
delete *LinkedChannel;
*LinkedChannel = NextLinkedChannel;
}
// Trigger Channel Events
LinkFunction->UpdateChannelOutState( LinkChannel );
UpdateChannelOutState( Channel );
return true;
}
//---------------------------------------------------------------------------
int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len )
{
TChannel * Channel = NULL;
// Validate
if (!ChannelName || !Data) {
if (!ChannelName || !*ChannelName || !Data) {
return 0;
}
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0;
}
else if (!Channel->InputEnabled) {
// Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled",
ProcessName, Name, ChannelName );
else if (!Channel->InState) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->InState] );
return 0;
}
else {
// Return processed bytes
if (Len == -1) {
Len = strlen( Data );
}
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
return Len;
// Return processed bytes
if (Len == -1) {
Len = strlen( Data );
}
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return Len;
}
//---------------------------------------------------------------------------
int CFunctionCore::Output( const char * ChannelName, const char * Data, int Len )
int CFunctionCore::Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len )
{
TChannel * Channel = NULL;
// Validate
if (!ChannelName) {
if (!ChannelName || !*ChannelName) {
return 0;
}
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel not found",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Output rejected, Output Channel not found",
ProcessName, Name, ChannelName, ((TargetRef && *TargetRef)? TargetRef : "(All)") );
return 0;
}
else {
// Return processed bytes
return Output( Channel, Data, Len );
return Output( Channel, TargetRef, SourceRef, Data, Len );
}
}
//---------------------------------------------------------------------------
int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat )
int CFunctionCore::Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat )
{
TChannelLink * OutChannel = NULL;
TChannelLink * LinkChannel = NULL;
int TempLen = 0;
int OutLen = 0;
@@ -363,123 +449,23 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len,
return 0;
}
// Check if enabled
if (!Channel->OutputEnabled) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel output disabled",
ProcessName, Name, Channel->Name );
return 0;
}
// Log event
if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:",
ProcessName, Name, Channel->Name );
if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s'->'%s' - OUT:",
ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") );
// Pass output to all linked inputs
if (Len == -1) {
if (Len == -1)
Len = strlen( Data );
}
OutChannel = Channel->FirstOutput;
while (OutChannel) {
TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len );
OutLen = (TempLen > OutLen)? TempLen : OutLen;
OutChannel = OutChannel->Next;
LinkChannel = Channel->FirstLink;
while (LinkChannel) {
if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) {
TempLen = LinkChannel->Function->Input( LinkChannel->Channel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len );
OutLen = (TempLen > OutLen)? TempLen : OutLen;
}
LinkChannel = LinkChannel->Next;
}
// Return processed bytes
return OutLen;
}
//---------------------------------------------------------------------------
bool CFunctionCore::PullInput( const char * ChannelName )
{
TChannel * Channel = NULL;
// Validate
if (!ChannelName) {
return false;
}
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input failed, Channel not found",
ProcessName, Name, ChannelName );
return false;
}
else {
// Return success
return PullInput( Channel );
}
}
//---------------------------------------------------------------------------
bool CFunctionCore::PullInput( TChannel * Channel )
{
TChannelLink * InChannel = NULL;
char ** Data = NULL;
int * Len = NULL;
// Validate
if (!Channel) {
return false;
}
// Check if enabled
if (!Channel->InputEnabled) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input failed, Channel input disabled",
ProcessName, Name, Channel->Name );
return false;
}
// Pass output to all linked inputs
InChannel = Channel->FirstInput;
while (InChannel)
{
// Pull Output from Channel
if (InChannel->Function->PullOutput( InChannel->Name, Data, Len ))
{
// Use input
Input( Channel->Name, *Data, ((*Len)? *Len : -1) );
}
InChannel = InChannel->Next;
}
// Return success
return Len;
}
//---------------------------------------------------------------------------
bool CFunctionCore::PullOutput( const char * ChannelName, char ** Data, int * Len )
{
TChannel * Channel = NULL;
int TempLen = 0;
// Validate
if (!ChannelName || !Data) {
return 0;
}
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output failed, Channel not found",
ProcessName, Name, ChannelName );
return 0;
}
else if (!Channel->InputEnabled) {
// Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output failed, Channel output disabled",
ProcessName, Name, ChannelName );
return 0;
}
else {
// Return processed bytes
*Data = StoredOutput;
TempLen = (*Data)? strlen(*Data) : 0;
if (Len) *Len = TempLen;
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, ((*Data)? *Data : "(NULL)"), TempLen, "%s/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
return Len;
}
}
//---------------------------------------------------------------------------

View File

@@ -17,6 +17,12 @@
//---------------------------------------------------------------------------
// Enumarate Types
typedef enum { CH_off = 0, CH_wait = 1, CH_ready = 2 } EChannelState;
const char ChannelStateName[][15] = { "Off", "Waiting", "Ready" };
//---------------------------------------------------------------------------
// Preview
typedef struct SChannel TChannel;
typedef struct SChannelLink TChannelLink;
@@ -28,12 +34,12 @@ class CFunctionCore;
struct SChannel
{
char * Name = NULL;
char * Ref = NULL;
TChannelLink * FirstInput = NULL;
TChannelLink * FirstOutput = NULL;
TChannelLink * FirstLink = NULL; // List of channels linked for input/output
bool InputEnabled = NULL;
bool OutputEnabled = NULL;
EChannelState InState = CH_off; // Channel ready to receive input (determined by parent function)
EChannelState OutState = CH_off; // Channel ready to send output (determined by InStates of linked channels)
TChannel * Next = NULL;
};
@@ -42,7 +48,10 @@ struct SChannel
struct SChannelLink
{
CFunctionCore * Function = NULL;
char * Name = NULL;
TChannel * Channel = NULL;
bool Input = false;
bool Output = false;
SChannelLink * Next = NULL;
};
@@ -62,6 +71,9 @@ protected:
char * Name = NULL;
bool WaitToTerminate = false;
// JSON Config
CDataMember * Config = NULL;
// Channels
TChannel * FirstChannel = NULL;
@@ -70,10 +82,6 @@ protected:
EDebugLevel LogLevel = dlNone;
int LogOutput = loNone;
// Stored Output
char * StoredOutput = NULL;
int StoredOutputLen = 0;
// Manage Channel
inline TChannel * GetChannel( const char * pName ) {
if (!pName) return NULL;
@@ -82,10 +90,16 @@ protected:
Channel = Channel->Next;
return Channel;
}
inline TChannelLink * GetLinkChannel( TChannel * Channel, const char * LinkRef ) {
if (!Channel || !LinkRef ) return NULL;
SChannelLink * LinkChannel = Channel->FirstLink;
while (LinkChannel && strcmp( LinkRef, LinkChannel->Channel->Ref ))
LinkChannel = LinkChannel->Next;
return LinkChannel;
}
// Data Input/Output
virtual int Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat = loNone );
virtual bool PullInput( TChannel * Channel );
virtual int Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat = loNone );
public:
// Life cycle
@@ -105,39 +119,20 @@ public:
inline const char * GetType() { return Type; };
// Manage Channels
virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true );
inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) {
TChannel * Channel = GetChannel( ChannelName );
if (!Channel) return false;
Channel->OutputEnabled = pOutputEnable;
return true;
}
inline bool SetChannelInEnable( const char * ChannelName, const bool pInputEnable ) {
TChannel * Channel = GetChannel( ChannelName );
if (!Channel) return false;
Channel->InputEnabled = pInputEnable;
return true;
}
inline bool isInputEnabled( const char * ChannelName ) {
TChannel * Channel = GetChannel( ChannelName );
return ((Channel)? Channel->InputEnabled : false);
}
inline bool isOutputEnabled( const char * ChannelName ) {
TChannel * Channel = GetChannel( ChannelName );
return ((Channel)? Channel->OutputEnabled : false);
}
virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State );
virtual bool SetChannelInState( TChannel * Channel, const EChannelState State );
virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { return true; };
virtual bool UpdateChannelOutState( TChannel * Channel );
virtual EChannelState GetChannelOutState( TChannel * Channel, const char * TargetRef );
// Pushing Data Output -> Input
virtual int Output( const char * ChannelName, const char * Data, int Len = -1 );
virtual int Input( const char * ChannelName, const char * Data, int Len = -1 );
// Pulling Data Input <- Output
virtual bool PullInput( const char * ChannelName );
virtual bool PullOutput( const char * ChannelName, char ** Data, int * Len = NULL );
virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 );
virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
// Automated Data Input/Output
virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional );
virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional );
virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output );
virtual bool UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName );
virtual bool Process() = 0;
friend class CApplication;

View File

@@ -272,7 +272,7 @@ bool CJSONparse::ReadFromHandle( const char * BasePath, int Handle, bool pRefill
InputHandle = Handle;
// Load Buffer
CreateBuffer( 500 );
CreateBuffer( 1000 );
if (!FillBuffer()) {
Error = true;
sprintf( ErrorText, "Could not read from file" );
@@ -690,7 +690,7 @@ bool CJSONparse::ParseArray( CDataMember * Array )
SkipWhiteSpace();
if (!ParseObject( *Member ) && !Error && !ParseArray( *Member ) && !Error && !ParseString( *Member ) && !Error && !ParsePrimitive( *Member ) ) {}
if (Error) {
delete Member;
delete *Member;
return false;
}
else {

View File

@@ -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" };

View File

@@ -38,9 +38,6 @@ CSelectableBare::CSelectableBare( const char * pName, const char * pType ) : CFu
{
// Quick access
Selector = Application->Selector;
// Handles
FirstHandle = NULL;
}
//---------------------------------------------------------------------------
@@ -97,7 +94,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
if (!*Handle)
{
// Create File handle at end of list
*Handle = (THandle*)calloc( 1, sizeof(THandle) );
*Handle = new THandle;
// Set name
if (HandleName) {
@@ -106,7 +103,8 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
}
// Set File Descriptor
(*Handle)->FD = -1;
(*Handle)->Function = this;
(*Handle)->FD = -1;
// Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created",
@@ -115,7 +113,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
// Create Matching Channel
if (CreateChannel) {
(*Handle)->Channel = AddChannel( HandleName );
(*Handle)->Channel = AddChannel( HandleName, CH_off );
}
return *Handle;
@@ -162,61 +160,39 @@ bool CSelectableBare::DestroyHandle( THandle * Handle )
free( Handle->Name );
if (Handle->Path)
free( Handle->Path );
if (Handle->HostName)
free( Handle->HostName );
if (Handle->PortName)
free( Handle->PortName );
if (Handle->AddressInfo)
freeaddrinfo( Handle->AddressList );
// Destroy Buffers
if (Handle->InBuffer)
delete Handle->InBuffer;
if (Handle->OutBuffer)
delete Handle->OutBuffer;
// Clear Input Markers
if (Handle->InMarker)
free( Handle->InMarker );
// Destroy Pointer
free( Handle );
delete Handle;
return true;
}
//---------------------------------------------------------------------------
bool CSelectableBare::ClearHandle( THandle * Handle )
bool CSelectableBare::HandleState( THandle * Handle, EConnectState State )
{
EChannelState ChannelState = CH_off;
// Validate
if (!Handle) {
if (!Handle || (Handle->State == State))
return false;
}
// Reset Type related parameters
if (Handle->Path) {
free( Handle->Path );
Handle->Path = NULL;
}
if (Handle->HostName) {
free( Handle->HostName );
Handle->HostName = NULL;
}
if (Handle->PortName) {
free( Handle->PortName );
Handle->PortName = NULL;
}
if (Handle->AddressList) {
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
}
// Set Call back
if (Handle->StateCallback[ (int)State ])
(Handle->StateCallback[ (int)State ])( this, Handle, State );
// Reset Parameters
Handle->Type = ctNone;
// Change state
Handle->State = State;
// Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None",
ProcessName, Name, Handle->Name );
// Update Channel
if (Handle->Channel) {
if ((Handle->State == csPreparing) || (Handle->State == csPrepared) || (Handle->State == csWaitingtoOpen))
ChannelState = CH_wait;
else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting))
ChannelState = CH_ready;
else
ChannelState = CH_off;
if (Handle->Channel->InState != ChannelState)
SetChannelInState( Handle->Channel, ChannelState );
}
return true;
}
//---------------------------------------------------------------------------
@@ -322,9 +298,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len );
Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else {
Output( Handle->Channel, Data, Len );
Output( Handle->Channel, NULL, true, Data, Len );
}
// Clear processed bytes from buffer
@@ -342,9 +318,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len );
Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else {
Output( Handle->Channel, Data, Len );
Output( Handle->Channel, NULL, true, Data, Len );
}
// Clear processed bytes from buffer
@@ -355,10 +331,11 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
}
//---------------------------------------------------------------------------
int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
int CSelectableBare::Open( THandle * Handle )
{
THandle * NewHandle = NULL;
// Validate
if (!Handle || (Handle->Type == ctNone)) {
return -1;
@@ -394,11 +371,11 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
Selector->Add( Handle->FD, true, false, Handle, this );
}
// Set state
ChangeState( Handle, csOpen );
// Set timer (for re-open or auto-close)
SetStartTime( &Handle->LastAction );
// Set state
HandleState( Handle, csOpen );
return (NewHandle)? NewHandle->FD : -1;
};
//---------------------------------------------------------------------------
@@ -414,7 +391,16 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
// Close Handle
Fail = (close( Handle->FD ))? true : false;
ChangeState( Handle, ((Fail)? csFailed : csClosed) );
// Remove from Select List
if (!Fail && Selector) {
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
// Start timer (for re-open)
if (QuickReopen)
@@ -426,15 +412,8 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s",
ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") );
// Remove from Select List
if (!Fail && Selector) {
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
// Set State
HandleState( Handle, ((Fail)? csFailed : csClosed) );
return true;
}
//---------------------------------------------------------------------------
@@ -534,7 +513,7 @@ bool CSelectableBare::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Attempt to re-open port
Open( Handle, true );
Open( Handle );
}
}
@@ -678,7 +657,7 @@ int CSelectableBare::WriteToFD( int FD, const char * Data, int Len, bool Force )
}
//---------------------------------------------------------------------------
int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len )
int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len )
{
TChannel * Channel = NULL;
THandle * Handle = NULL;
@@ -694,20 +673,20 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0;
}
else if (!Channel->InputEnabled) {
else if (Channel->InState != CH_ready) {
// Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0;
}
// Log event
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
// Find Linked handle
Handle = FirstHandle;
@@ -725,8 +704,8 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
if (!HandleCount) {
// Handle not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles found",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, No Handles found",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0;
}
@@ -752,11 +731,11 @@ int CSelectableBare::OutputHandle( THandle * Handle, const char * Data, int Len
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Complete opening process
Open( Handle, true );
Open( Handle );
// Check if Handle is open
if (Handle->State == csOpenRequest) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle",
if ((Handle->State == csPreparing) || (Handle->State == csPrepared)) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Preparing (auto-managed) Handle",
ProcessName, Name, Handle->Name );
return 0;
}
@@ -833,27 +812,21 @@ bool CSelectableBare::Process()
while (Handle)
{
// Auto manage handles
if ((Handle->State == csOpenRequest))
{
// Resolve then open socket
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
Open( Handle, false );
}
if (Handle->State == csPrepared) {
// Proceed to open
Open( Handle );
}
else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) )
{
else if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) {
// Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) {
Open( Handle, false );
Open( Handle );
}
}
// Check Input buffers
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0))
{
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) {
// Check duration since last PortIn
if (Timeout( Handle->InStart, Handle->InTimeout ))
{
if (Timeout( Handle->InStart, Handle->InTimeout )) {
// Process Input
ProcessInputBuffer( Handle, true );
@@ -863,95 +836,14 @@ bool CSelectableBare::Process()
}
// Check for auto close (but not on servers)
if ((Handle->State == csOpen) && (Handle->Type != ctTCPserver) && (Handle->Type != ctUNIXserver) && Handle->AutoManage && !Handle->Persistent)
{
if ((Handle->State == csOpen) && Handle->AutoManage && !Handle->Persistent) {
// Close port after timeout
if (Timeout( Handle->LastAction, Handle->CloseTimeout )) {
Close( Handle, true );
}
}
Handle = Handle->Next;
}
return true;
}
//---------------------------------------------------------------------------
bool CSelectableBare::BuildArgs( const char * ExecPath, int &Count, char * Args[] )
{
bool ParamStarted = false;
bool OpenQuotes = false;
char * MatchPos = NULL;
char * StartPos = NULL;
int Len;
// Validate
if (!ExecPath || !*ExecPath) {
return false;
}
// Split params
MatchPos = (char*)ExecPath;
for (;;)
{
// Look for whitespace
if (!ParamStarted)
{
// Quotes starts quoted parameter
if (*MatchPos == '"') {
ParamStarted = true;
OpenQuotes = true;
StartPos = MatchPos+1; // Skip starting quote
}
// Non-whitespace starts normal parameter
else if ((*MatchPos != ' ') && (*MatchPos != 0)) {
ParamStarted = true;
StartPos = MatchPos;
}
}
else if (OpenQuotes)
{
// Another quote ends parameter
if (*MatchPos == '"') {
Len = MatchPos-StartPos-1; // Skip end quote
Args[Count] = (char*)malloc( Len+1 );
strncpy( Args[Count], StartPos, Len );
Args[Count][Len] = 0;
Count++;
ParamStarted = false;
OpenQuotes = false;
}
}
else
{
// Whitespace ends parameter
if ((*MatchPos == ' ') || (*MatchPos == 0)) {
Len = MatchPos-StartPos;
Args[Count] = (char*)malloc( Len+1 );
strncpy( Args[Count], StartPos, Len );
Args[Count][Len] = 0;
Count++;
ParamStarted = false;
}
}
// Next char, unless NULL
if (*MatchPos)
MatchPos++;
else
break;
}
// Check all parameters closed
if (ParamStarted) {
Count = 0;
Args[0] = NULL;
return false;
}
// Set last Param to NULL
Args[Count] = NULL;
return true;
}
//---------------------------------------------------------------------------

View File

@@ -40,24 +40,57 @@ CFunctionCore * NewSelectableCore( const char * Name ) {
}
//---------------------------------------------------------------------------
// Resolve action handlder
void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context )
{
TResolveReq * ResolveReq;
THandle * Handle;
// Validate signal
if ((SignalInfo->si_code != SI_ASYNCNL) ||
(SignalInfo->si_signo != SIGRTMIN))
return;
// Get Handle & Request
ResolveReq = (TResolveReq*)(SignalInfo->si_value.sival_ptr);
Handle = ResolveReq->Handle;
((CSelectableCore*)Handle->Function)->HandleResolve( Handle );
}
//---------------------------------------------------------------------------
CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CSelectableBare( pName, pType )
{
// Quick access
Selector = Application->Selector;
// Configure resolve signal handler
ResolveAct.sa_sigaction = &ResolveHandler;
sigemptyset( &ResolveAct.sa_mask );
ResolveAct.sa_flags = SA_SIGINFO;
sigaction( SIGRTMIN, &ResolveAct, NULL );
}
//---------------------------------------------------------------------------
CSelectableCore::~CSelectableCore()
{
THandle * NextHandle = NULL;
bool Result;
// Destroy File Handles
while (FirstHandle)
{
// Close active resolve request
if (FirstHandle->ResolveReq) {
if ((Result = gai_cancel( FirstHandle->ResolveReq->Request )) != 0) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)",
ProcessName, Name, FirstHandle->Name, FirstHandle->HostName, FirstHandle->PortName, gai_strerror(Result) );
DestroyResolveReq( FirstHandle, true );
HandleState( FirstHandle, csFailed );
}
}
// Close handle if open
if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) {
Close( FirstHandle, false );
}
if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen))
Close( FirstHandle, false );
NextHandle = FirstHandle->Next;
DestroyHandle( FirstHandle );
@@ -81,7 +114,6 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
short Parity;
short FlowCtrl;
short Queue;
long Delay;
// Call Previous load config
if (!CFunctionCore::Init( FunctionConfig ))
@@ -177,8 +209,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
}
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0, Delay );
SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0 );
}
else if (!strcasecmp( Type, "UDPclient" ))
{
@@ -189,8 +220,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
}
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0, Delay );
SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0 );
}
else if (!strcasecmp( Type, "TCPserver" ))
{
@@ -201,9 +231,8 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
}
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true );
SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Queue, Delay );
SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Queue );
}
else if (!strcasecmp( Type, "TCPclient" ))
{
@@ -214,8 +243,7 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
}
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0, Delay );
SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0 );
}
else if (!strcasecmp( Type, "ForkPipe" )) {
Address = (char*)HandleConfig->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value
@@ -243,6 +271,87 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
}
//---------------------------------------------------------------------------
bool CSelectableCore::DestroyHandle( THandle * Handle )
{
int Result;
// Validate Handle
if (!Handle)
return false;
// Destroy Resolve request
if (Handle->ResolveReq) {
if ((Result = gai_cancel( Handle->ResolveReq->Request )) != 0) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) );
}
DestroyResolveReq( Handle, true );
}
// Clear parameters
if (Handle->Name)
free( Handle->Name );
if (Handle->Path)
free( Handle->Path );
if (Handle->HostName)
free( Handle->HostName );
if (Handle->PortName)
free( Handle->PortName );
if (Handle->AddressList)
freeaddrinfo( Handle->AddressList );
// Destroy Buffers
if (Handle->InBuffer)
delete Handle->InBuffer;
if (Handle->OutBuffer)
delete Handle->OutBuffer;
// Clear Input Markers
if (Handle->InMarker)
free( Handle->InMarker );
// Destroy Pointer
delete Handle;
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::ClearHandle( THandle * Handle )
{
// Validate
if (!Handle) {
return false;
}
// Reset Type related parameters
if (Handle->Path) {
free( Handle->Path );
Handle->Path = NULL;
}
if (Handle->HostName) {
free( Handle->HostName );
Handle->HostName = NULL;
}
if (Handle->PortName) {
free( Handle->PortName );
Handle->PortName = NULL;
}
if (Handle->AddressList) {
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
}
// Reset Parameters
Handle->Type = ctNone;
// Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None",
ProcessName, Name, Handle->Name );
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetSerialHandle( THandle * Handle, const char * FileName )
{
// Validate
@@ -353,7 +462,7 @@ bool CSelectableCore::SetUnixHandle( THandle * Handle, EConnectType Type, const
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay )
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue )
{
// Validate
if (!Handle || !HostName || !PortName ||
@@ -364,7 +473,6 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
// Set Type
Handle->Type = Type;
Handle->ResolveDelay = ResolveDelay;
// Clear HostName & Port Name
if (Handle->HostName)
@@ -443,7 +551,7 @@ THandle * CSelectableCore::OpenSerialPort( THandle * Handle )
}
// Set state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
@@ -486,7 +594,7 @@ THandle * CSelectableCore::OpenLinePrinterPort( THandle * Handle )
}
// Set state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
@@ -588,7 +696,7 @@ THandle * CSelectableCore::OpenForkPipe( THandle * Handle )
}
// Set state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
@@ -612,7 +720,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
}
@@ -624,7 +732,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -648,7 +756,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
// Set state
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -662,7 +771,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
// Set state
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -676,7 +786,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
}
// Set state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
@@ -702,7 +812,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -729,7 +839,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
}
// Set status
ChangeState( Handle, csWaitingtoOpen );
HandleState( Handle, csWaitingtoOpen );
return Handle;
}
else
@@ -745,11 +855,10 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
// Close socket
close( Handle->FD );
ChangeState( Handle, csFailed );
Handle->FD = -1;
Handle->AddressFailed = true;
// Reset Handle
Handle->FD = -1;
HandleState( Handle, csFailed );
return NULL;
}
}
@@ -764,7 +873,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
}
// Set status
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
}
@@ -861,7 +970,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path );
// Update state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
}
@@ -869,14 +978,19 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle )
}
//---------------------------------------------------------------------------
bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
bool CSelectableCore::ResolveAddress( THandle * Handle )
{
struct addrinfo hints;
int result;
struct addrinfo * Hints;
TResolveReq * ResolveReq;
sigevent ResolveEvt;
int Result;
// Ignore if busy resolving
if (Handle->State == csPreparing)
return false;
// Check if resolved address available
if (Handle->AddressInfo)
{
if (Handle->AddressInfo) {
// Return if address still valid
if (!Handle->AddressFailed)
return true;
@@ -907,47 +1021,108 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
}
// Set address specification
memset( &hints, 0, sizeof hints );
Hints = (struct addrinfo*)calloc( 1, sizeof(struct addrinfo) );
if ((Handle->Type == ctTCPserver) || (Handle->Type == ctTCPclient)) {
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
Hints->ai_socktype = SOCK_STREAM;
} else {
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_DGRAM;
Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
Hints->ai_socktype = SOCK_DGRAM;
}
// Create request data
ResolveReq = new TResolveReq;
Handle->ResolveReq = ResolveReq;
ResolveReq->Handle = Handle;
ResolveReq->Request = (gaicb*)calloc( 1, sizeof(gaicb) );
// DNS request / reply structure
ResolveReq->Request->ar_name = Handle->HostName;
ResolveReq->Request->ar_service = Handle->PortName;
ResolveReq->Request->ar_request = Hints;
ResolveReq->Request->ar_result = NULL;
// Configure signal event
ResolveEvt.sigev_notify = SIGEV_SIGNAL;
ResolveEvt.sigev_signo = SIGRTMIN;
ResolveEvt.sigev_value.sival_ptr = ResolveReq;
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Resolving Host name [%s:%s]...",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName );
// Should address be resolved later during process()
if (DelayResolve)
{
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Delay resolving of Host Name [%s:%s]",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName );
ChangeState( Handle, csOpenRequest );
// Resolve Host & Port Names
HandleState( Handle, csPreparing );
if ((Result = getaddrinfo_a( GAI_NOWAIT, &(Handle->ResolveReq->Request), 1, &ResolveEvt )) != 0) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) );
DestroyResolveReq( Handle, true );
HandleState( Handle, csFailed );
SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve
return false;
}
return false;
}
//---------------------------------------------------------------------------
bool CSelectableCore::DestroyResolveReq( THandle * Handle, bool DestroyResult )
{
// Validate
if (!Handle || !Handle->ResolveReq)
return false;
// Destroy
if (DestroyResult) {
if (Handle->ResolveReq->Request->ar_result)
freeaddrinfo( Handle->ResolveReq->Request->ar_result );
}
if (Handle->ResolveReq->Request->ar_request)
free( (void*)Handle->ResolveReq->Request->ar_request );
if (Handle->ResolveReq->Request)
free( Handle->ResolveReq->Request );
if (Handle->ResolveReq)
delete Handle->ResolveReq;
// Reset request
Handle->ResolveReq = NULL;
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::HandleResolve( THandle * Handle )
{
bool Result;
// Validate result
if ((Result = gai_error( Handle->ResolveReq->Request )) != 0) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) );
DestroyResolveReq( Handle, true );
HandleState( Handle, csFailed );
SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve
return false;
}
// Resolve Host & Port Names
if ((result = getaddrinfo( Handle->HostName, Handle->PortName, &hints, &(Handle->AddressList))) != 0)
{
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) );
ChangeState( Handle, csFailed );
return false;
}
// Read result
Handle->AddressList = Handle->ResolveReq->Request->ar_result;
Handle->AddressInfo = Handle->AddressList;
// Select first address, skip "0.0.0.0"
Handle->AddressInfo = Handle->AddressList;
if (!strcmp( inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr), "0.0.0.0" ))
Handle->AddressInfo = Handle->AddressInfo->ai_next;
if (!Handle->AddressInfo) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) );
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (No Result)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName );
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve
return false;
}
@@ -956,11 +1131,15 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName,
inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr),
ntohs(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port) );
// Destroy request
DestroyResolveReq( Handle, false );
HandleState( Handle, csPrepared );
return true;
}
//---------------------------------------------------------------------------
THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayResolve )
THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle )
{
// Validate Handle
if (Handle->Type != ctUDPserver) {
@@ -968,7 +1147,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
}
// Resolve Host & Port Names
if (!ResolveAddress( Handle, DelayResolve ))
if (!ResolveAddress( Handle ))
return NULL;
// Create socket
@@ -979,7 +1158,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -994,11 +1173,13 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to bind UDP socket [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
// Close handle
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true;
// Change state
HandleState( Handle, csFailed );
return NULL;
};
@@ -1012,7 +1193,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
}
// Set state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
@@ -1042,7 +1223,7 @@ THandle * CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientA
// Create Remote Client Handle
sprintf( ClientName, "%s-%d", Handle->Name, ClientCount );
*RemoteClient = CreateHandle( ClientName, false );
if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0, 0 )) {
if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0 )) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - UDP Server failed to configure Remote Client connection (%s)",
ProcessName, Name, Handle->Name, strerror(errno) );
return NULL;
@@ -1074,7 +1255,7 @@ THandle * CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientA
}
//---------------------------------------------------------------------------
THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayResolve )
THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle )
{
// Check state
if (Handle->State == csOpen) {
@@ -1083,7 +1264,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso
}
// Resolve IP Address
if (!ResolveAddress( Handle, DelayResolve ))
if (!ResolveAddress( Handle ))
return NULL;
// Create File descriptor
@@ -1094,7 +1275,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set Status
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -1111,12 +1292,12 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso
}
// Set status
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayResolve )
THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle )
{
// Socket options
struct linger ServerLinger_opt;
@@ -1135,7 +1316,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
}
// Resolve Host & Port Names
if (!ResolveAddress( Handle, DelayResolve ))
if (!ResolveAddress( Handle ))
return NULL;
// Create socket
@@ -1146,7 +1327,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -1159,7 +1340,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
}
@@ -1174,7 +1355,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
}
@@ -1189,11 +1370,12 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to bind TCP Server socket [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
// Close handle
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true;
HandleState( Handle, csFailed );
return NULL;
};
@@ -1204,11 +1386,12 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to listen on TCP Server socket [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
// Close handle
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true;
HandleState( Handle, csFailed );
return NULL;
};
@@ -1222,7 +1405,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
}
// Set state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
//---------------------------------------------------------------------------
@@ -1270,7 +1453,6 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
strcpy( ClientAddress, inet_ntoa(address.sin_addr) );
sprintf( ClientPort, "%d", ntohs(address.sin_port) );
// Get end of client list
RemoteClient = &FirstHandle;
while (*RemoteClient) {
@@ -1280,7 +1462,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
// Create Remote Client Handle
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
*RemoteClient = CreateHandle( ClientName, false );
if (!SetSocketHandle( *RemoteClient, ctTCPremote, ClientAddress, ClientPort, 0, 0 )) {
if (!SetSocketHandle( *RemoteClient, ctTCPremote, ClientAddress, ClientPort, 0 )) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - TCP Server failed to configure Remote Client connection (%s)",
ProcessName, Name, Handle->Name, strerror(errno) );
return NULL;
@@ -1325,7 +1507,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->HostName );
// Update state
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
}
@@ -1333,13 +1515,14 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
}
//---------------------------------------------------------------------------
THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayResolve )
THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle )
{
// Socket options
int KeepAlive_opt = 1;
int TCPidle_opt = 5;
int TCPcnt_opt = 3;
int TCPint_opt = 2;
int KeepAlive_opt = 1; // Enable/disable keep alive
int TCPidle_opt = 5; // Idle time on socket before sending first keep alive signal
int TCPint_opt = 2; // Interval between keep alive signals
int TCPcnt_opt = 3; // No of missed keep alive response before connection fail
int TCPsyn_opt = 3; // Max SYN (connect retries) before open fails
// Check state
if (Handle->State == csOpen) {
@@ -1350,7 +1533,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
if (Handle->State != csWaitingtoOpen)
{
// Resolve IP Address
if (!ResolveAddress( Handle, DelayResolve ))
if (!ResolveAddress( Handle ))
return NULL;
// Create File descriptor
@@ -1361,7 +1544,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set Status
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
};
@@ -1373,16 +1556,18 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
if ((setsockopt( Handle->FD, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_SYNCNT, &TCPsyn_opt, sizeof(TCPsyn_opt)) == -1) )
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set State
// Close handle
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL;
}
}
@@ -1399,7 +1584,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
}
// Set status
ChangeState( Handle, csOpen );
HandleState( Handle, csOpen );
return Handle;
}
else if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EALREADY))
@@ -1414,7 +1599,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
}
// Set status
ChangeState( Handle, csWaitingtoOpen );
HandleState( Handle, csWaitingtoOpen );
return Handle;
}
else
@@ -1430,17 +1615,16 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
// Close socket
close( Handle->FD );
ChangeState( Handle, csFailed );
Handle->FD = -1;
Handle->AddressFailed = true;
// Reset Handle
Handle->FD = -1;
HandleState( Handle, csFailed );
return NULL;
}
}
//---------------------------------------------------------------------------
int CSelectableCore::Open( THandle * Handle, bool DelayResolve )
int CSelectableCore::Open( THandle * Handle )
{
THandle * NewHandle = NULL;
@@ -1467,16 +1651,16 @@ int CSelectableCore::Open( THandle * Handle, bool DelayResolve )
NewHandle = OpenUNIXclientSocket( Handle );
break;
case ctUDPserver :
NewHandle = OpenUDPserverSocket( Handle, DelayResolve );
NewHandle = OpenUDPserverSocket( Handle );
break;
case ctUDPclient :
NewHandle = OpenUDPclientSocket( Handle, DelayResolve );
NewHandle = OpenUDPclientSocket( Handle );
break;
case ctTCPserver :
NewHandle = OpenTCPserverSocket( Handle, DelayResolve );
NewHandle = OpenTCPserverSocket( Handle );
break;
case ctTCPclient :
NewHandle = OpenTCPclientSocket( Handle, DelayResolve );
NewHandle = OpenTCPclientSocket( Handle );
break;
default:
NewHandle = NULL;
@@ -1532,7 +1716,16 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
} else {
Fail = (close( Handle->FD ))? true : false;
}
ChangeState( Handle, ((Fail)? csFailed : csClosed) );
// Remove from Select List
if (!Fail && Selector) {
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
// Start timer (for re-open)
if (QuickReopen)
@@ -1616,15 +1809,8 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
break;
};
// Remove from Select List
if (!Fail && Selector) {
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
// Change State
HandleState( Handle, ((Fail)? csFailed : csClosed) );
return true;
}
//---------------------------------------------------------------------------
@@ -1680,7 +1866,7 @@ bool CSelectableCore::Read( THandle * Handle )
if (Handle->Type == ctTCPremote) {
OpenTCPremoteSocket( Handle );
} else if (Handle->Type == ctTCPclient) {
OpenTCPclientSocket( Handle, true );
OpenTCPclientSocket( Handle );
} else if (Handle->Type == ctUNIXremote) {
OpenUNIXremoteSocket( Handle );
} else if (Handle->Type == ctUNIXclient) {
@@ -1842,7 +2028,7 @@ bool CSelectableCore::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Attempt to re-open port
Open( Handle, true );
Open( Handle );
}
}
@@ -1856,7 +2042,7 @@ bool CSelectableCore::Write( THandle * Handle )
if (Handle->Type == ctTCPremote) {
OpenTCPremoteSocket( Handle );
} else if (Handle->Type == ctTCPclient) {
OpenTCPclientSocket( Handle, true );
OpenTCPclientSocket( Handle );
} else if (Handle->Type == ctUNIXremote) {
OpenUNIXremoteSocket( Handle );
} else if (Handle->Type == ctUNIXclient) {
@@ -2007,11 +2193,11 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Complete opening process
Open( Handle, true );
Open( Handle );
// Check if Handle is open
if (Handle->State == csOpenRequest) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle",
if (Handle->State == csPreparing) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Resolving (auto-managed) Handle",
ProcessName, Name, Handle->Name );
return 0;
}
@@ -2153,16 +2339,14 @@ bool CSelectableCore::Process()
while (Handle)
{
// Auto manage handles
if ((Handle->State == csOpenRequest)) {
// Resolve then open socket
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
Open( Handle, false );
}
if (Handle->State == csPrepared) {
// Proceed to open
Open( Handle );
}
else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) ) {
else if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) {
// Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) {
Open( Handle, false );
Open( Handle );
}
}
@@ -2471,3 +2655,80 @@ bool CSelectableCore::ReadSerialConfig( THandle * Handle )
}
//---------------------------------------------------------------------------
bool CSelectableCore::BuildArgs( const char * ExecPath, int &Count, char * Args[] )
{
bool ParamStarted = false;
bool OpenQuotes = false;
char * MatchPos = NULL;
char * StartPos = NULL;
int Len;
// Validate
if (!ExecPath || !*ExecPath) {
return false;
}
// Split params
MatchPos = (char*)ExecPath;
for (;;)
{
// Look for whitespace
if (!ParamStarted)
{
// Quotes starts quoted parameter
if (*MatchPos == '"') {
ParamStarted = true;
OpenQuotes = true;
StartPos = MatchPos+1; // Skip starting quote
}
// Non-whitespace starts normal parameter
else if ((*MatchPos != ' ') && (*MatchPos != 0)) {
ParamStarted = true;
StartPos = MatchPos;
}
}
else if (OpenQuotes)
{
// Another quote ends parameter
if (*MatchPos == '"') {
Len = MatchPos-StartPos-1; // Skip end quote
Args[Count] = (char*)malloc( Len+1 );
strncpy( Args[Count], StartPos, Len );
Args[Count][Len] = 0;
Count++;
ParamStarted = false;
OpenQuotes = false;
}
}
else
{
// Whitespace ends parameter
if ((*MatchPos == ' ') || (*MatchPos == 0)) {
Len = MatchPos-StartPos;
Args[Count] = (char*)malloc( Len+1 );
strncpy( Args[Count], StartPos, Len );
Args[Count][Len] = 0;
Count++;
ParamStarted = false;
}
}
// Next char, unless NULL
if (*MatchPos)
MatchPos++;
else
break;
}
// Check all parameters closed
if (ParamStarted) {
Count = 0;
Args[0] = NULL;
return false;
}
// Set last Param to NULL
Args[Count] = NULL;
return true;
}
//---------------------------------------------------------------------------

View File

@@ -10,6 +10,8 @@
// Standard C/C++ Libraries
#include <ctype.h>
#include <signal.h>
#include <netdb.h>
// redA Libraries
#include "FunctionCore.h"
@@ -22,8 +24,8 @@ typedef enum { ctNone = 0, ctSerial = 1, ctLinePrinter = 2, ctForkPipe = 3, ctUN
const char ConnectTypeName[][20] = { "None", "Serial Port", "Line Printer", "Fork Pipe", "UNIX Server", "UNIX Client", "UNIX Remote Client",
"UDP Server", "UDP Client", "UDP Remote Client", "TCP Server", "TCP Client", "TCP Remote Client", "Custom" };
typedef enum { csNone = 0, csOpenRequest = 1, csWaitingtoOpen = 2, csOpen = 3, csDataWaiting = 4, csClosed = 5, csFailed = 6 } EConnectState;
const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" };
typedef enum { csNone = 0, csPreparing = 1, csPrepared = 2, csWaitingtoOpen = 3, csOpen = 4, csDataWaiting = 5, csClosed = 6, csFailed = 7 } EConnectState;
const char ConnectStateName[][15] = { "None", "Preparing", "Prepared", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" };
//---------------------------------------------------------------------------
@@ -44,13 +46,14 @@ const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "O
// Previews
typedef struct SSelectHandle TSelectHandle;
typedef struct SHandle THandle;
typedef struct SResolveReq TResolveReq;
class CSelect;
class CSelectableBare;
class CSelectableCore;
// Callback function for handle events
typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState State );
typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState OldState );
//---------------------------------------------------------------------------
@@ -68,7 +71,6 @@ struct SSelectHandle {
// List
TSelectHandle * Next = NULL;
};
//---------------------------------------------------------------------------
// List or Handles for Selectable Function Object
@@ -76,6 +78,7 @@ struct SHandle {
// Description
char * Name = NULL;
EConnectType Type = ctNone;
CSelectableBare * Function = NULL;
// State
int FD = -1;
@@ -88,7 +91,7 @@ struct SHandle {
long CloseTimeout = 1000; // millisecs of no traffic before closing socket
// Callback functions
FHandleCallback StateCallback[ 7 ] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
FHandleCallback StateCallback[ 8 ] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
// Type specific parameters
char * Path = NULL; // Port (file)name or Exec path
@@ -103,7 +106,8 @@ struct SHandle {
struct addrinfo * AddressInfo = NULL; // Current selected IP Address
bool AddressFailed = false; // Indicate failure to connect to address
short Queue = 2; // Max waiting connections
long ResolveDelay = 0; // Delay before resolving hostname via DNS
TResolveReq * ResolveReq = NULL; // DNS resolve request
// Serial Port config
bool SerialConfig = false;
@@ -132,6 +136,16 @@ struct SHandle {
THandle * Parent = NULL;
THandle * Next = NULL;
};
//---------------------------------------------------------------------------
struct SResolveReq {
THandle * Handle = NULL;
gaicb * Request = NULL;
};
//---------------------------------------------------------------------------
// Resolving
void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context );
//---------------------------------------------------------------------------
@@ -192,8 +206,9 @@ protected:
CSelect * Selector = NULL;
// Managing File Handles
bool RemoveHandle( THandle * Handle );
bool DestroyHandle( THandle * Handle );
virtual bool RemoveHandle( THandle * Handle );
virtual bool DestroyHandle( THandle * Handle );
virtual bool HandleState( THandle * Handle, EConnectState State );
// Get Parameters
inline int GetFD( const char * HandleName ) {
@@ -201,15 +216,6 @@ protected:
return ((Handle)? Handle->FD : -1);
};
// General fucntions
inline bool ChangeState( THandle * Handle, EConnectState State ) {
if (!Handle || (Handle->State == State)) return false;
if (Handle->StateCallback[ (int)State ])
(Handle->StateCallback[ (int)State ])( this, Handle, State );
Handle->State = State;
return true;
}
// Mutual Operations
int ReadFromFD( int FD, char * Data, int MaxLen );
int WriteToFD( int FD, const char * Data, int Len, bool Force );
@@ -217,9 +223,6 @@ protected:
// Buffer operations
virtual bool ProcessInputBuffer( THandle * Handle, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
// Convert string to lower case
inline char * strlcase( char * Str ) {
for (char * Ch = Str; *Ch; Ch++ )
@@ -233,19 +236,17 @@ public:
virtual ~CSelectableBare();
// Configuration
virtual bool Init( CDataMember * FunctionConfig ) = 0;
virtual bool Init( CDataMember * FunctionConfig ) = 0;
// Finding Handles
inline THandle * GetHandle( const char * HandleName )
{
inline THandle * GetHandle( const char * HandleName ) {
if (!HandleName) return NULL;
THandle * Handle = FirstHandle;
while ( Handle && strcmp( HandleName, Handle->Name ))
Handle = Handle->Next;
return Handle;
}
inline THandle * GetHandle( int FD )
{
inline THandle * GetHandle( int FD ) {
if (FD < 0) return NULL;
THandle * Handle = FirstHandle;
while ( Handle && (FD != Handle->FD))
@@ -254,7 +255,7 @@ public:
}
// General port parameters
THandle * CreateHandle( const char * HandleName, bool CreateChannel );
virtual THandle * CreateHandle( const char * HandleName, bool CreateChannel );
virtual CDataMember * GetHandleAddress( THandle * Handle, const char * HandleRef );
bool SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback );
@@ -262,17 +263,14 @@ public:
bool SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen );
bool SetOutBuffer( THandle * Handle, int OutBufSize );
// Specific port parameters
bool ClearHandle( THandle * Handle );
// FD Operations
virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0;
virtual int Open( THandle * Handle ) = 0;
virtual bool Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle );
// FD operations
inline virtual int Open( const char * HandleName, bool DelayResolve = false ) { return (Open( GetHandle( HandleName ), DelayResolve)); };
inline virtual int Open( const char * HandleName ) { return (Open( GetHandle( HandleName ))); };
inline virtual bool Close( const char * HandleName, bool QuickReopen ) { return (Close( GetHandle( HandleName ), QuickReopen )); };
inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); };
@@ -294,8 +292,8 @@ public:
};
// Function Interface
virtual int Input( const char * ChannelName, const char * Buffer, int BufLen = -1 );
int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process();
};
@@ -304,6 +302,8 @@ public:
class CSelectableCore : public CSelectableBare
{
protected:
struct sigaction ResolveAct;
// Port Operations
THandle * OpenSerialPort( THandle * Handle );
bool WriteSerialConfig( THandle * Handle );
@@ -318,18 +318,27 @@ protected:
THandle * OpenUNIXremoteSocket( THandle * Handle );
// Socket Operations
bool ResolveAddress( THandle * Handle, bool DelayResolve );
THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve );
bool ResolveAddress( THandle * Handle );
bool HandleResolve( THandle * Handle );
bool DestroyResolveReq( THandle * Handle, bool DestroyResult );
// Managing File Handles
virtual bool DestroyHandle( THandle * Handle );
THandle * OpenUDPserverSocket( THandle * Handle );
THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort );
THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve );
THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve );
THandle * OpenUDPclientSocket( THandle * Handle );
THandle * OpenTCPserverSocket( THandle * Handle );
THandle * OpenTCPremoteSocket( THandle * Handle );
THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve );
THandle * OpenTCPclientSocket( THandle * Handle );
// Mutual Operations
int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen );
int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
public:
// Life Cycle
CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE );
@@ -339,22 +348,26 @@ public:
virtual bool Init( CDataMember * FunctionConfig );
// Specific port parameters
bool ClearHandle( THandle * Handle );
bool SetSerialHandle( THandle * Handle, const char * FileName );
bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait );
bool SetLinePrinterHandle( THandle * Handle, const char * FileName );
bool SetForkPipeHandle( THandle * Handle, const char * ExecPath );
bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue );
bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay );
bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue );
// FD Operations
virtual int Open( THandle * Handle, bool DelayResolve = false );
virtual int Open( THandle * Handle );
virtual bool Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle );
// Function Interface
int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process();
friend void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context );
};
//---------------------------------------------------------------------------

View File

@@ -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 );
}
//---------------------------------------------------------------------------

View File

@@ -12,6 +12,7 @@
#include <sys/time.h>
#include <time.h>
#include <limits.h>
#include <stdio.h>
// 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_ */

View File

@@ -40,7 +40,10 @@ char * BytesToSafeStr( const char * Bytes, const int Len, const bool NoCrLf, con
// Remove special char
for (int i=0; i<Len; i++) {
if (((Bytes[i] < 32) || (Bytes[i] > 126)) ||
if ((Bytes[i] == '\r') || (Bytes[i] == '\n')) {
*BufPos = (NoCrLf)? SpecChar : Bytes[i];
}
else if (((Bytes[i] < 32) || (Bytes[i] > 126)) ||
(NoCrLf && ((Bytes[i] == '\r') || (Bytes[i] == '\n')))) {
*BufPos = SpecChar;
}
@@ -75,7 +78,7 @@ char * BytesToHexStr( const char * Bytes, const int Len, const char * Separator,
// Print Hex values of individual bytes
for (int i=0; i<Len; i++) {
sprintf( BufPos, "%s%02X", ((First)? "" : Separator), (unsigned char)Bytes[i] );
sprintf( BufPos, "%s%02X", ((First || !Separator)? "" : Separator), (unsigned char)Bytes[i] );
BufPos += (First)? 2 : 2+SepLen;
First = false;
}
@@ -105,7 +108,7 @@ char * BytesToBinStr( const char * Bytes, const int Len, const char * Separator,
// Print each byte as 8-bit binary
for (int i=0; i<Len; i++) {
sprintf( BufPos, "%s%c%c%c%c%c%c%c%c", ((First)? "" : Separator),
sprintf( BufPos, "%s%c%c%c%c%c%c%c%c", ((First || !Separator)? "" : Separator),
(Bytes[i] & 0x80)?'1':'0', (Bytes[i] & 0x40)?'1':'0', (Bytes[i] & 0x20)?'1':'0', (Bytes[i] & 0x10)?'1':'0',
(Bytes[i] & 0x08)?'1':'0', (Bytes[i] & 0x04)?'1':'0', (Bytes[i] & 0x02)?'1':'0', (Bytes[i] & 0x01)?'1':'0' );
BufPos += (First)? 8 : 8+SepLen;

View File

@@ -28,8 +28,8 @@ inline u_int8_t HexToInt( char Digit ) {
else if ((Digit >= 'a') && (Digit <= 'f')) return (Digit - 'a'+10);
else return 0;
}
char * HexStrToBytes( const char * Str, const int Len, const char * Separator, char * OutBuf );
char * BinStrToBytes( const char * Str, const int Len, const char *Separator = NULL, char * OutBuf = NULL );
char * HexStrToBytes( const char * Str, const int Len, const char * Separator = NULL, char * OutBuf = NULL );
char * BinStrToBytes( const char * Str, const int Len, const char * Separator = NULL, char * OutBuf = NULL );
// Search string data
char * StrSearch( const char * Haystack, const char * Needle, const int hLen = 0, const int nLen = 0 );

View File

@@ -63,7 +63,7 @@ bool CWatchdogCore::Init( CDataMember * FunctionConfig )
return false;
// Set specific parameters
SetInterval( FunctionConfig->GetChInt( "Parameters/PingInterval", 500, true ));
SetInterval( Config->GetChInt( "PingInterval", 500, true ));
// Create handle and set reference, if not done
if (!(Ping = GetHandle( "Ping" )))