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 // Set signal handlers
ConfigureSignalHandlers(); ConfigureSignalHandlers();
DefinitionFile = NULL; DefinitionFile = NULL;
ConfigFile = NULL; ConfigFile = NULL;
AddressFile = NULL; AddressFile = NULL;
// Create output logger // Create output logger
Log = new CLogCore( stdout ); Log = new CLogCore( stdout );
@@ -420,9 +420,9 @@ bool CApplication::Run( bool TerminateOnError )
{ {
ProcessTerminate = !FunctionItem->Function->Process(); ProcessTerminate = !FunctionItem->Function->Process();
if (TerminateOnError) { if (TerminateOnError) {
if (ProcessTerminate) if (ProcessTerminate) // Raise terminate flag for other processes
Terminate = true; Terminate = true;
if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) // If needed, allow process to terminate cleanly
CleanTerminate = false; CleanTerminate = false;
} }
} }

View File

@@ -131,10 +131,8 @@ CDataMember * CDataMember::CreateChild( const char * Name, const int Len )
bool CDataMember::Clear() bool CDataMember::Clear()
{ {
// Clear value // Clear value
if (Value) { if (Value)
free( Value ); free( Value );
Value = NULL;
}
// Clear children // Clear children
while (FirstChild) { while (FirstChild) {
@@ -142,7 +140,9 @@ bool CDataMember::Clear()
} }
// Reset value // Reset value
Type = jtNull; Type = jtNull;
Value = NULL;
Len = 0;
return true; 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 ) bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds )
{ {
struct tm NewTime; struct tm NewTime;
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
// Get current date and time // Get current Epoch (UTC)
gettimeofday( &tv, &tz); gettimeofday( &tv, &tz);
// Change to new time // Convert to local time
localtime_r( &tv.tv_sec, &NewTime ); localtime_r( &tv.tv_sec, &NewTime );
// Set new time (keep date as is)
NewTime.tm_hour = Hours; NewTime.tm_hour = Hours;
NewTime.tm_min = Minutes; NewTime.tm_min = Minutes;
NewTime.tm_sec = Seconds; NewTime.tm_sec = Seconds;
// Convert back // Convert back from local time to epoch time
tv.tv_sec = mktime( &NewTime ); tv.tv_sec = mktime( &NewTime );
tv.tv_usec = 0; 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 ) bool SetDate( unsigned char Day, unsigned char Month, unsigned Year )
{ {
struct tm NewDate; struct tm NewDate;
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
// Get current date and time // Get current Epoch (UTC)
gettimeofday( &tv, &tz ); gettimeofday( &tv, &tz );
// Change to new time // Convert to local time
localtime_r( &tv.tv_sec, &NewDate ); localtime_r( &tv.tv_sec, &NewDate );
// Set new date (keep time as is)
NewDate.tm_year = Year - 1900; NewDate.tm_year = Year - 1900;
NewDate.tm_mon = Month - 1; NewDate.tm_mon = Month - 1;
NewDate.tm_mday = Day; NewDate.tm_mday = Day;
// Convert back // Convert back from local time to epoch time
tv.tv_sec = mktime( &NewDate ); tv.tv_sec = mktime( &NewDate );
tv.tv_usec = 0; 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 ) bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year )
{ {
struct tm CurrentDate; struct tm CurrentDate;
time_t UTC; time_t UTC;
// Get current date and time // Get current UTC date and time
time( &UTC ); time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentDate ); localtime_r( &UTC, &CurrentDate );
// Extract date // Extract date only
Day = CurrentDate.tm_mday; Day = CurrentDate.tm_mday;
Month = CurrentDate.tm_mon + 1; Month = CurrentDate.tm_mon + 1;
Year = CurrentDate.tm_year + 1900; 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 ) char const * GetDateStr( const char * DateSeparator )
{ {
unsigned char Day; unsigned char Day;
@@ -172,12 +230,15 @@ char const * GetDateTimeStr( const char * DateSeparator, const char * TimeSepar
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Get current time from real-time clock // 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; struct tm CurrentTime;
// Get current date and time // Get current date and time
localtime_r( &EpochTime, &CurrentTime ); if (LocalTime)
localtime_r( &EpochTime, &CurrentTime );
else
gmtime_r( &EpochTime, &CurrentTime );
// Extract time // Extract time
Hours = CurrentTime.tm_hour; 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; struct tm CurrentDate;
// Get current date and time // Get current date and time
localtime_r( &EpochTime, &CurrentDate ); if (LocalTime)
localtime_r( &EpochTime, &CurrentDate );
else
gmtime_r( &EpochTime, &CurrentDate );
// Extract date // Extract date
Day = CurrentDate.tm_mday; 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 // 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 Day;
unsigned char Month; unsigned char Month;
unsigned int Year; unsigned int Year;
// Get Date // Get Date
ReadDate( EpochTime, Day, Month, Year ); ReadDate( EpochTime, LocalTime, Day, Month, Year );
// Build String // Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d", 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 Hours;
unsigned char Minutes; unsigned char Minutes;
unsigned char Seconds; unsigned char Seconds;
// Get Date & Time // Get Date & Time
ReadTime( EpochTime, Hours, Minutes, Seconds ); ReadTime( EpochTime, LocalTime, Hours, Minutes, Seconds );
// Build String // Build String
sprintf( ReturnStr, "%02d%s%02d%s%02d", 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 Day;
unsigned char Month; unsigned char Month;
@@ -250,8 +417,7 @@ char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparato
unsigned char Seconds; unsigned char Seconds;
// Get Date & Time // Get Date & Time
ReadDate( EpochTime, Day, Month, Year ); ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds );
ReadTime( EpochTime, Hours, Minutes, Seconds );
// Build String // Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", 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 // 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 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 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 * GetDateStr( const char * DateSeparator = "/" );
char const * GetTimeStr( const char * TimeSeparator = ":" ); 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 ); // Build or interpret time data
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year ); 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 = "/" ); bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime );
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator = ":" ); bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year );
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" ); 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 // Global Vars
extern char * ProcessName; 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 ) CDeviceCore::CDeviceCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
{ {
// Polling // Polling
PollCycle = 0;
PollStep = 0;
PollInterval = 250;
SetStartTime( &PollWait ); SetStartTime( &PollWait );
WaitingForReply = false;
ReplyTimeout = 200;
InvalidReply = false;
PollRetry = 0;
MaxRetries = 3;
// Data Structures // Data Structures
DeviceInit = true;
ConfigTypes = new CDataMember(); ConfigTypes = new CDataMember();
ValueTree = new CDataMember(); ValueTree = new CDataMember();
JSONparse = new CJSONparse(); JSONparse = new CJSONparse();
@@ -69,7 +58,6 @@ CDeviceCore::~CDeviceCore()
bool CDeviceCore::Init( CDataMember * FunctionConfig ) bool CDeviceCore::Init( CDataMember * FunctionConfig )
{ {
char * PersistFile = NULL; char * PersistFile = NULL;
char * ConfigName = NULL;
CDataMember * PollConfig = NULL; CDataMember * PollConfig = NULL;
int IntVal1; int IntVal1;
int IntVal2; int IntVal2;
@@ -80,18 +68,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig )
// Add Channels // Add Channels
if (!(CmdChannel = GetChannel( "Command" ))) if (!(CmdChannel = GetChannel( "Command" )))
CmdChannel = AddChannel( "Command", true, true ); CmdChannel = AddChannel( "Command", CH_ready );
if (!(DeviceChannel = GetChannel( "Device" ))) else
DeviceChannel = AddChannel( "Device", true, true ); SetChannelInState( CmdChannel, CH_ready );
if (!(EventChannel = GetChannel( "Event" )))
EventChannel = AddChannel( "Event", true, true );
// Get configuration if (!(DeviceChannel = GetChannel( "Device" )))
if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) { DeviceChannel = AddChannel( "Device", CH_ready );
ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); else
Config = Application->Config->GetChild( ConfigName, true ); SetChannelInState( DeviceChannel, CH_ready );
}
if (Config->isNull()) Config->SetObject(); if (!(EventChannel = GetChannel( "Event" )))
EventChannel = AddChannel( "Event", CH_ready );
else
SetChannelInState( EventChannel, CH_ready );
// Load Polling configuration // Load Polling configuration
PollConfig = Config->GetChild( "Polling", true ); PollConfig = Config->GetChild( "Polling", true );
@@ -442,6 +431,7 @@ bool CDeviceCore::SetPollParam( int pPollInterval )
bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries ) bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries )
{ {
DefReplyTimeout = pReplyTimeout;
ReplyTimeout = pReplyTimeout; ReplyTimeout = pReplyTimeout;
MaxRetries = pMaxRetries; MaxRetries = pMaxRetries;
return true; return true;
@@ -466,12 +456,13 @@ bool CDeviceCore::DeviceOnline( TDevice * Device, bool Online )
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CDeviceCore::SetWaitForReply() void CDeviceCore::SetWaitForReply( int CustomTimeout )
{ {
// Start timer // Start timer
SetStartTime( &PollWait ); SetStartTime( &PollWait );
// Set flag // Set flag
ReplyTimeout = (CustomTimeout >= 0)? CustomTimeout : DefReplyTimeout;
WaitingForReply = true; WaitingForReply = true;
InvalidReply = false; 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; int Len;
char Value[50]; char Value[50];
@@ -1671,7 +1662,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
} }
else { else {
strcat( OutputStr, "\n" ); 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", Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Get",
ProcessName, Name, ChannelName, OutputStr ); ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" ); strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
} }
} }
else if (!strcasecmp( "set", Value )) else if (!strcasecmp( "set", Value ))
@@ -1717,7 +1708,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
} }
else { else {
sprintf( OutputStr, "> set %s,%s = %s\n", Device->Name, Param->Name, Value ); 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", Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Set",
ProcessName, Name, ChannelName, OutputStr ); ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" ); strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
} }
} }
else if (!strcasecmp( "status", Value )) else if (!strcasecmp( "status", Value ))
@@ -1746,7 +1737,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
} }
else { else {
sprintf( OutputStr, "> %s - %s\n", Device->Name, ((Device->Online)? "online" : "offline") ); sprintf( OutputStr, "> %s - %s\n", Device->Name, ((Device->Online)? "online" : "offline") );
Output( ChannelName, OutputStr ); Output( ChannelName, NULL, true, OutputStr );
} }
// Report error // 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", Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Status",
ProcessName, Name, ChannelName, OutputStr ); ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" ); strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
} }
} }
else 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", Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s', %s%s",
ProcessName, Name, ChannelName, Value, OutputStr ); ProcessName, Name, ChannelName, Value, OutputStr );
strcat( OutputStr, " (comma separated values)\n" ); strcat( OutputStr, " (comma separated values)\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
} }
return MaxLen; return MaxLen;
} }
@@ -1819,7 +1810,7 @@ bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force )
default : default :
break; break;
} }
Output( Param->EventChannel, Message, strlen(Message) ); Output( Param->EventChannel, NULL, true, Message, strlen(Message) );
// Reset timer // Reset timer
if (Param->EventInterval) { if (Param->EventInterval) {

View File

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

View File

@@ -73,7 +73,7 @@ public:
virtual bool SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout ); virtual bool SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout );
// Data Input // 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 // Processing data
virtual bool Process(); 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 ) CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( pType )
{ {
// Set name // Set name
if (pName) { if (pName)
Name = strdup( pName ); Name = strdup( pName );
}
// Logging // Logging
Log = Application->Log; Log = Application->Log;
@@ -44,35 +43,19 @@ CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( p
CFunctionCore::~CFunctionCore() CFunctionCore::~CFunctionCore()
{ {
TChannel * NextChannel = NULL; TChannel * NextChannel = NULL;
TChannelLink * NextLinkedChannel = NULL;
// Destroy Channels // Destroy Channels
while (FirstChannel) while (FirstChannel)
{ {
// Destroy Linked Channels
while (FirstChannel->FirstLink)
UnlinkChannel( FirstChannel->Name, FirstChannel->FirstLink->Function->Name, FirstChannel->FirstLink->Channel->Name );
// Destroy Parameters // Destroy Parameters
if (FirstChannel->Name) { if (FirstChannel->Name)
free( FirstChannel->Name ); free( FirstChannel->Name );
} if (FirstChannel->Ref)
free( FirstChannel->Ref );
// 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;
}
// Destroy Channel // Destroy Channel
NextChannel = FirstChannel->Next; NextChannel = FirstChannel->Next;
@@ -95,11 +78,15 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
CDataMember * ChannelConfig; CDataMember * ChannelConfig;
EDebugLevel pLogLevel; EDebugLevel pLogLevel;
int pLogOutput; int pLogOutput;
char * ConfigName = NULL;
// Validate // Validate
if (!FunctionConfig ) if (!FunctionConfig )
return false; return false;
// Set Type
FunctionConfig->SetChStr( "Type", Type );
// Configure Logging/Debugging // Configure Logging/Debugging
LogConfig = FunctionConfig->GetChild( "Log", true ); LogConfig = FunctionConfig->GetChild( "Log", true );
pLogLevel = Log->ReadLogLevel( LogConfig ); pLogLevel = Log->ReadLogLevel( LogConfig );
@@ -108,16 +95,17 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
// Load Channels // Load Channels
ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true );
while (ChannelConfig) while (ChannelConfig) {
{ AddChannel( ChannelConfig->GetName(), CH_off );
if (ChannelConfig->GetName()) {
AddChannel( ChannelConfig->GetName(),
ChannelConfig->GetChBool( "InputEnabled", true, true ),
ChannelConfig->GetChBool( "OutputEnabled", false, true ));
}
ChannelConfig = ChannelConfig->GetNextPeer(); 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; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -142,10 +130,11 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig )
while (FunctionMember) while (FunctionMember)
{ {
// Get Parameters // Get Parameters
LinkOutputChannel( Channel->Name, LinkChannel( Channel->Name,
FunctionMember->GetChStr( "Function" ), FunctionMember->GetChStr( "Function", NULL, true ),
FunctionMember->GetChStr( "Channel" ), FunctionMember->GetChStr( "Channel", NULL, true ),
FunctionMember->GetChBool( "Bidirectional" ) ); FunctionMember->GetChBool( "Input", false, true ),
FunctionMember->GetChBool( "Output", false, true ) );
FunctionMember = FunctionMember->GetNextPeer(); 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; TChannel ** Channel = NULL;
@@ -195,166 +184,263 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu
// Set Name // Set Name
(*Channel)->Name = strdup( ChannelName ); (*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 // Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created", if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', In:%s, Out:%s",
ProcessName, Name, ChannelName ); ProcessName, Name, ChannelName, (*Channel)->Ref,
ChannelStateName[(*Channel)->InState], ChannelStateName[(*Channel)->OutState]);
} }
// Set parameters
(*Channel)->InputEnabled = pInputEnable;
(*Channel)->OutputEnabled = pOutputEnable;
return *Channel; return *Channel;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Automated Data Input/Output bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State )
bool CFunctionCore::LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional )
{ {
CFunctionCore * OutFunction = NULL; EChannelState OldState = Channel->InState;
TChannel * Channel = NULL; TChannelLink * LinkChannel;
TChannelLink ** LinkedChannel = NULL;
// Get Channel // Validate
if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) { if (!Channel)
return false; return false;
}
// Check if linked Channel exists // Update state
LinkedChannel = &(Channel->FirstInput); Channel->InState = State;
while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s",
LinkedChannel = &((*LinkedChannel)->Next); ProcessName, Name, Channel->Ref, ChannelStateName[State] );
}
// Create if not found // Update linked channels
if (!*LinkedChannel) LinkChannel = Channel->FirstLink;
{ while (LinkChannel) {
// Create if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s",
*LinkedChannel = new TChannelLink; ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] );
// Set Parameters // Trigger Linked Channel Events
(*LinkedChannel)->Function = OutFunction; LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel );
(*LinkedChannel)->Name = strdup( OutChannelName ); LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State );
// Log Event LinkChannel = LinkChannel->Next;
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Input Linked - '%s'/'%s' <-- '%s'/'%s'",
ProcessName, Name, Name, ChannelName, OutFunction->GetName(), OutChannelName );
}
// Link Return direction as well
if (Bidirectional) {
return OutFunction->LinkInputChannel( OutChannelName, Name, ChannelName, false );
} }
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ) bool CFunctionCore::UpdateChannelOutState( TChannel * Channel )
{ {
TChannel * OutChannel = NULL; TChannelLink * LinkChannel;
CFunctionCore * InFunction = NULL; EChannelState OutState;
TChannel * InChannel = NULL;
// 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; TChannelLink ** LinkedChannel = NULL;
// Check if Channels & Function exist // Check if Channels & Function exist
if (!(OutChannel = GetChannel( ChannelName )) || if (!(Channel = GetChannel( ChannelName )) ||
!(InFunction = Application->GetFunction( InFunctionName )) || !(LinkFunction = Application->GetFunction( LinkFunctionName )) ||
!(InChannel = InFunction->GetChannel( InChannelName )) ) { !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) {
return false; return false;
} }
// Check if linked Channel exists // Check if linked Channel exists
LinkedChannel = &(OutChannel->FirstOutput); LinkedChannel = &(Channel->FirstLink);
while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) { while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel))
LinkedChannel = &((*LinkedChannel)->Next); LinkedChannel = &((*LinkedChannel)->Next);
}
// Create if not found
if (!*LinkedChannel) if (!*LinkedChannel)
{
// Create
*LinkedChannel = new TChannelLink; *LinkedChannel = new TChannelLink;
// Set Parameters // Set Parameters
(*LinkedChannel)->Function = InFunction; (*LinkedChannel)->Function = LinkFunction;
(*LinkedChannel)->Name = strdup( InChannelName ); (*LinkedChannel)->Channel = LinkChannel;
(*LinkedChannel)->Input = Input;
(*LinkedChannel)->Output = Output;
// Log Event // Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s'/'%s' --> '%s'/'%s'", if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Linked - '%s'-->'%s' - In:%s, Out:%s",
ProcessName, Name, Name, ChannelName, InFunction->GetName(), InChannelName ); ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref, ((Input)? "Yes" : "No"), ((Output)? "Yes" : "No") );
}
// Link return direction as well // Find Linked channel on remote function
if (Bidirectional) { LinkedChannel = &(LinkChannel->FirstLink);
return InFunction->LinkOutputChannel( InChannelName, Name, ChannelName, false ); 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; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Manual Data Input/Output bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName )
int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len )
{ {
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 // Validate
if (!ChannelName || !Data) { if (!ChannelName || !*ChannelName || !Data) {
return 0; return 0;
} }
// Get Channel // Get Channel
if (!(Channel = GetChannel( ChannelName ))) { if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found // Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
else if (!Channel->InputEnabled) { else if (!Channel->InState) {
// Channel disabled if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s",
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->InState] );
ProcessName, Name, ChannelName );
return 0; return 0;
} }
else {
// Return processed bytes // Return processed bytes
if (Len == -1) { if (Len == -1) {
Len = strlen( Data ); Len = strlen( Data );
}
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
return Len;
} }
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; TChannel * Channel = NULL;
// Validate // Validate
if (!ChannelName) { if (!ChannelName || !*ChannelName) {
return 0; return 0;
} }
// Get Channel // Get Channel
if (!(Channel = GetChannel( ChannelName ))) { if (!(Channel = GetChannel( ChannelName ))) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel not found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Output rejected, Output Channel not found",
ProcessName, Name, ChannelName ); ProcessName, Name, ChannelName, ((TargetRef && *TargetRef)? TargetRef : "(All)") );
return 0; return 0;
} }
else { else {
// Return processed bytes // 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 TempLen = 0;
int OutLen = 0; int OutLen = 0;
@@ -363,123 +449,23 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len,
return 0; 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 // Log event
if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:", if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s'->'%s' - OUT:",
ProcessName, Name, Channel->Name ); ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") );
// Pass output to all linked inputs // Pass output to all linked inputs
if (Len == -1) { if (Len == -1)
Len = strlen( Data ); Len = strlen( Data );
} LinkChannel = Channel->FirstLink;
OutChannel = Channel->FirstOutput; while (LinkChannel) {
while (OutChannel) { if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) {
TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len ); TempLen = LinkChannel->Function->Input( LinkChannel->Channel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len );
OutLen = (TempLen > OutLen)? TempLen : OutLen; OutLen = (TempLen > OutLen)? TempLen : OutLen;
OutChannel = OutChannel->Next; }
LinkChannel = LinkChannel->Next;
} }
// Return processed bytes // Return processed bytes
return OutLen; 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 // Preview
typedef struct SChannel TChannel; typedef struct SChannel TChannel;
typedef struct SChannelLink TChannelLink; typedef struct SChannelLink TChannelLink;
@@ -28,12 +34,12 @@ class CFunctionCore;
struct SChannel struct SChannel
{ {
char * Name = NULL; char * Name = NULL;
char * Ref = NULL;
TChannelLink * FirstInput = NULL; TChannelLink * FirstLink = NULL; // List of channels linked for input/output
TChannelLink * FirstOutput = NULL;
bool InputEnabled = NULL; EChannelState InState = CH_off; // Channel ready to receive input (determined by parent function)
bool OutputEnabled = NULL; EChannelState OutState = CH_off; // Channel ready to send output (determined by InStates of linked channels)
TChannel * Next = NULL; TChannel * Next = NULL;
}; };
@@ -42,7 +48,10 @@ struct SChannel
struct SChannelLink struct SChannelLink
{ {
CFunctionCore * Function = NULL; CFunctionCore * Function = NULL;
char * Name = NULL; TChannel * Channel = NULL;
bool Input = false;
bool Output = false;
SChannelLink * Next = NULL; SChannelLink * Next = NULL;
}; };
@@ -62,6 +71,9 @@ protected:
char * Name = NULL; char * Name = NULL;
bool WaitToTerminate = false; bool WaitToTerminate = false;
// JSON Config
CDataMember * Config = NULL;
// Channels // Channels
TChannel * FirstChannel = NULL; TChannel * FirstChannel = NULL;
@@ -70,10 +82,6 @@ protected:
EDebugLevel LogLevel = dlNone; EDebugLevel LogLevel = dlNone;
int LogOutput = loNone; int LogOutput = loNone;
// Stored Output
char * StoredOutput = NULL;
int StoredOutputLen = 0;
// Manage Channel // Manage Channel
inline TChannel * GetChannel( const char * pName ) { inline TChannel * GetChannel( const char * pName ) {
if (!pName) return NULL; if (!pName) return NULL;
@@ -82,10 +90,16 @@ protected:
Channel = Channel->Next; Channel = Channel->Next;
return Channel; 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 // Data Input/Output
virtual int Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat = loNone ); virtual int Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat = loNone );
virtual bool PullInput( TChannel * Channel );
public: public:
// Life cycle // Life cycle
@@ -105,39 +119,20 @@ public:
inline const char * GetType() { return Type; }; inline const char * GetType() { return Type; };
// Manage Channels // Manage Channels
virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true ); virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State );
inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) {
TChannel * Channel = GetChannel( ChannelName ); virtual bool SetChannelInState( TChannel * Channel, const EChannelState State );
if (!Channel) return false; virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { return true; };
Channel->OutputEnabled = pOutputEnable; virtual bool UpdateChannelOutState( TChannel * Channel );
return true; virtual EChannelState GetChannelOutState( TChannel * Channel, const char * TargetRef );
}
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 // Pushing Data Output -> Input
virtual int Output( const char * ChannelName, const char * Data, int Len = -1 ); 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 * Data, int Len = -1 ); virtual int Input( const char * ChannelName, const char * SourceRef, 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 );
// Automated Data Input/Output // Automated Data Input/Output
virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional ); virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output );
virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ); virtual bool UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName );
virtual bool Process() = 0; virtual bool Process() = 0;
friend class CApplication; friend class CApplication;

View File

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

View File

@@ -17,7 +17,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Global vars // 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" }; 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 // Quick access
Selector = Application->Selector; Selector = Application->Selector;
// Handles
FirstHandle = NULL;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -97,7 +94,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
if (!*Handle) if (!*Handle)
{ {
// Create File handle at end of list // Create File handle at end of list
*Handle = (THandle*)calloc( 1, sizeof(THandle) ); *Handle = new THandle;
// Set name // Set name
if (HandleName) { if (HandleName) {
@@ -106,7 +103,8 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
} }
// Set File Descriptor // Set File Descriptor
(*Handle)->FD = -1; (*Handle)->Function = this;
(*Handle)->FD = -1;
// Log event // Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created", 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 // Create Matching Channel
if (CreateChannel) { if (CreateChannel) {
(*Handle)->Channel = AddChannel( HandleName ); (*Handle)->Channel = AddChannel( HandleName, CH_off );
} }
return *Handle; return *Handle;
@@ -162,61 +160,39 @@ bool CSelectableBare::DestroyHandle( THandle * Handle )
free( Handle->Name ); free( Handle->Name );
if (Handle->Path) if (Handle->Path)
free( 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 // Destroy Pointer
free( Handle ); delete Handle;
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CSelectableBare::ClearHandle( THandle * Handle ) bool CSelectableBare::HandleState( THandle * Handle, EConnectState State )
{ {
EChannelState ChannelState = CH_off;
// Validate // Validate
if (!Handle) { if (!Handle || (Handle->State == State))
return false; return false;
}
// Reset Type related parameters // Set Call back
if (Handle->Path) { if (Handle->StateCallback[ (int)State ])
free( Handle->Path ); (Handle->StateCallback[ (int)State ])( this, Handle, State );
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 // Change state
Handle->Type = ctNone; Handle->State = State;
// Log event // Update Channel
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", if (Handle->Channel) {
ProcessName, Name, Handle->Name ); 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; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -322,9 +298,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs // Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) { if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len ); Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else { } else {
Output( Handle->Channel, Data, Len ); Output( Handle->Channel, NULL, true, Data, Len );
} }
// Clear processed bytes from buffer // Clear processed bytes from buffer
@@ -342,9 +318,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs // Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) { if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len ); Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else { } else {
Output( Handle->Channel, Data, Len ); Output( Handle->Channel, NULL, true, Data, Len );
} }
// Clear processed bytes from buffer // 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; THandle * NewHandle = NULL;
// Validate // Validate
if (!Handle || (Handle->Type == ctNone)) { if (!Handle || (Handle->Type == ctNone)) {
return -1; return -1;
@@ -394,11 +371,11 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
Selector->Add( Handle->FD, true, false, Handle, this ); Selector->Add( Handle->FD, true, false, Handle, this );
} }
// Set state
ChangeState( Handle, csOpen );
// Set timer (for re-open or auto-close) // Set timer (for re-open or auto-close)
SetStartTime( &Handle->LastAction ); SetStartTime( &Handle->LastAction );
// Set state
HandleState( Handle, csOpen );
return (NewHandle)? NewHandle->FD : -1; return (NewHandle)? NewHandle->FD : -1;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -414,7 +391,16 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
// Close Handle // Close Handle
Fail = (close( Handle->FD ))? true : false; 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) // Start timer (for re-open)
if (QuickReopen) if (QuickReopen)
@@ -426,15 +412,8 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s", if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s",
ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") ); ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") );
// Remove from Select List // Set State
if (!Fail && Selector) { HandleState( Handle, ((Fail)? csFailed : csClosed) );
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -534,7 +513,7 @@ bool CSelectableBare::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{ {
// Attempt to re-open port // 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; TChannel * Channel = NULL;
THandle * Handle = NULL; THandle * Handle = NULL;
@@ -694,20 +673,20 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
// Get Channel // Get Channel
if (!(Channel = GetChannel( ChannelName ))) { if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found // Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
else if (!Channel->InputEnabled) { else if (Channel->InState != CH_ready) {
// Channel disabled // Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
// Log event // Log event
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:", if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
// Find Linked handle // Find Linked handle
Handle = FirstHandle; Handle = FirstHandle;
@@ -725,8 +704,8 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
if (!HandleCount) { if (!HandleCount) {
// Handle not found // Handle not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, No Handles found",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
@@ -752,11 +731,11 @@ int CSelectableBare::OutputHandle( THandle * Handle, const char * Data, int Len
else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{ {
// Complete opening process // Complete opening process
Open( Handle, true ); Open( Handle );
// Check if Handle is open // Check if Handle is open
if (Handle->State == csOpenRequest) { if ((Handle->State == csPreparing) || (Handle->State == csPrepared)) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Preparing (auto-managed) Handle",
ProcessName, Name, Handle->Name ); ProcessName, Name, Handle->Name );
return 0; return 0;
} }
@@ -833,27 +812,21 @@ bool CSelectableBare::Process()
while (Handle) while (Handle)
{ {
// Auto manage handles // Auto manage handles
if ((Handle->State == csOpenRequest)) if (Handle->State == csPrepared) {
{ // Proceed to open
// Resolve then open socket Open( Handle );
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
Open( Handle, false );
}
} }
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 // Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { if (Timeout( Handle->LastAction, Handle->ReopenDelay )) {
Open( Handle, false ); Open( Handle );
} }
} }
// Check Input buffers // Check Input buffers
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) {
{
// Check duration since last PortIn // Check duration since last PortIn
if (Timeout( Handle->InStart, Handle->InTimeout )) if (Timeout( Handle->InStart, Handle->InTimeout )) {
{
// Process Input // Process Input
ProcessInputBuffer( Handle, true ); ProcessInputBuffer( Handle, true );
@@ -863,95 +836,14 @@ bool CSelectableBare::Process()
} }
// Check for auto close (but not on servers) // 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 // Close port after timeout
if (Timeout( Handle->LastAction, Handle->CloseTimeout )) { if (Timeout( Handle->LastAction, Handle->CloseTimeout )) {
Close( Handle, true ); Close( Handle, true );
} }
} }
Handle = Handle->Next; Handle = Handle->Next;
} }
return true; 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 ) CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CSelectableBare( pName, pType )
{ {
// Quick access // Configure resolve signal handler
Selector = Application->Selector; ResolveAct.sa_sigaction = &ResolveHandler;
sigemptyset( &ResolveAct.sa_mask );
ResolveAct.sa_flags = SA_SIGINFO;
sigaction( SIGRTMIN, &ResolveAct, NULL );
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CSelectableCore::~CSelectableCore() CSelectableCore::~CSelectableCore()
{ {
THandle * NextHandle = NULL; THandle * NextHandle = NULL;
bool Result;
// Destroy File Handles // Destroy File Handles
while (FirstHandle) 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 // Close handle if open
if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) { if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen))
Close( FirstHandle, false ); Close( FirstHandle, false );
}
NextHandle = FirstHandle->Next; NextHandle = FirstHandle->Next;
DestroyHandle( FirstHandle ); DestroyHandle( FirstHandle );
@@ -81,7 +114,6 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
short Parity; short Parity;
short FlowCtrl; short FlowCtrl;
short Queue; short Queue;
long Delay;
// Call Previous load config // Call Previous load config
if (!CFunctionCore::Init( FunctionConfig )) 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 Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
} }
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0 );
SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0, Delay );
} }
else if (!strcasecmp( Type, "UDPclient" )) 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 Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
} }
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0 );
SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0, Delay );
} }
else if (!strcasecmp( Type, "TCPserver" )) 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 Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
} }
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true ); 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" )) 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 Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
} }
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true ); SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0 );
SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0, Delay );
} }
else if (!strcasecmp( Type, "ForkPipe" )) { else if (!strcasecmp( Type, "ForkPipe" )) {
Address = (char*)HandleConfig->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value 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 ) bool CSelectableCore::SetSerialHandle( THandle * Handle, const char * FileName )
{ {
// Validate // 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 // Validate
if (!Handle || !HostName || !PortName || if (!Handle || !HostName || !PortName ||
@@ -364,7 +473,6 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
// Set Type // Set Type
Handle->Type = Type; Handle->Type = Type;
Handle->ResolveDelay = ResolveDelay;
// Clear HostName & Port Name // Clear HostName & Port Name
if (Handle->HostName) if (Handle->HostName)
@@ -443,7 +551,7 @@ THandle * CSelectableCore::OpenSerialPort( THandle * Handle )
} }
// Set state // Set state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -486,7 +594,7 @@ THandle * CSelectableCore::OpenLinePrinterPort( THandle * Handle )
} }
// Set state // Set state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -588,7 +696,7 @@ THandle * CSelectableCore::OpenForkPipe( THandle * Handle )
} }
// Set state // Set state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -612,7 +720,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; return NULL;
} }
@@ -624,7 +732,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -648,7 +756,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
// Set state // Set state
close( Handle->FD ); close( Handle->FD );
Handle->FD = -1; Handle->FD = -1;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -662,7 +771,8 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
// Set state // Set state
close( Handle->FD ); close( Handle->FD );
Handle->FD = -1; Handle->FD = -1;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -676,7 +786,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
} }
// Set state // Set state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -702,7 +812,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -729,7 +839,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
} }
// Set status // Set status
ChangeState( Handle, csWaitingtoOpen ); HandleState( Handle, csWaitingtoOpen );
return Handle; return Handle;
} }
else else
@@ -745,11 +855,10 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
// Close socket // Close socket
close( Handle->FD ); close( Handle->FD );
ChangeState( Handle, csFailed ); Handle->FD = -1;
Handle->AddressFailed = true; Handle->AddressFailed = true;
// Reset Handle HandleState( Handle, csFailed );
Handle->FD = -1;
return NULL; return NULL;
} }
} }
@@ -764,7 +873,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle )
} }
// Set status // Set status
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
} }
@@ -861,7 +970,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->Path ); ProcessName, Name, Handle->Name, Handle->Path );
// Update state // Update state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; 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; struct addrinfo * Hints;
int result; TResolveReq * ResolveReq;
sigevent ResolveEvt;
int Result;
// Ignore if busy resolving
if (Handle->State == csPreparing)
return false;
// Check if resolved address available // Check if resolved address available
if (Handle->AddressInfo) if (Handle->AddressInfo) {
{
// Return if address still valid // Return if address still valid
if (!Handle->AddressFailed) if (!Handle->AddressFailed)
return true; return true;
@@ -907,47 +1021,108 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
} }
// Set address specification // Set address specification
memset( &hints, 0, sizeof hints ); Hints = (struct addrinfo*)calloc( 1, sizeof(struct addrinfo) );
if ((Handle->Type == ctTCPserver) || (Handle->Type == ctTCPclient)) { if ((Handle->Type == ctTCPserver) || (Handle->Type == ctTCPclient)) {
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM; Hints->ai_socktype = SOCK_STREAM;
} else { } else {
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_DGRAM; 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]...", if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Resolving Host name [%s:%s]...",
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName );
// Should address be resolved later during process() // Resolve Host & Port Names
if (DelayResolve) HandleState( Handle, csPreparing );
{
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Delay resolving of Host Name [%s:%s]", if ((Result = getaddrinfo_a( GAI_NOWAIT, &(Handle->ResolveReq->Request), 1, &ResolveEvt )) != 0) {
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)",
ChangeState( Handle, csOpenRequest ); 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; return false;
} }
// Resolve Host & Port Names // Read result
if ((result = getaddrinfo( Handle->HostName, Handle->PortName, &hints, &(Handle->AddressList))) != 0) Handle->AddressList = Handle->ResolveReq->Request->ar_result;
{ Handle->AddressInfo = Handle->AddressList;
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;
}
// Select first address, skip "0.0.0.0" // 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" )) if (!strcmp( inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr), "0.0.0.0" ))
Handle->AddressInfo = Handle->AddressInfo->ai_next; Handle->AddressInfo = Handle->AddressInfo->ai_next;
if (!Handle->AddressInfo) { if (!Handle->AddressInfo) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)", 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, gai_strerror(result) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName );
freeaddrinfo( Handle->AddressList ); freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL; Handle->AddressList = NULL;
Handle->AddressInfo = NULL; Handle->AddressInfo = NULL;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
SetStartTime( &Handle->LastAction ); // Allow delay before retrying resolve
return false; return false;
} }
@@ -956,11 +1131,15 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName,
inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr), inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr),
ntohs(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port) ); ntohs(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port) );
// Destroy request
DestroyResolveReq( Handle, false );
HandleState( Handle, csPrepared );
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayResolve ) THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle )
{ {
// Validate Handle // Validate Handle
if (Handle->Type != ctUDPserver) { if (Handle->Type != ctUDPserver) {
@@ -968,7 +1147,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
} }
// Resolve Host & Port Names // Resolve Host & Port Names
if (!ResolveAddress( Handle, DelayResolve )) if (!ResolveAddress( Handle ))
return NULL; return NULL;
// Create socket // Create socket
@@ -979,7 +1158,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; 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)", 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) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Close handle
close( Handle->FD ); close( Handle->FD );
Handle->FD = -1; Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true; Handle->AddressFailed = true;
// Change state
HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -1012,7 +1193,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso
} }
// Set state // Set state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -1042,7 +1223,7 @@ THandle * CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientA
// Create Remote Client Handle // Create Remote Client Handle
sprintf( ClientName, "%s-%d", Handle->Name, ClientCount ); sprintf( ClientName, "%s-%d", Handle->Name, ClientCount );
*RemoteClient = CreateHandle( ClientName, false ); *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)", 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) ); ProcessName, Name, Handle->Name, strerror(errno) );
return NULL; 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 // Check state
if (Handle->State == csOpen) { if (Handle->State == csOpen) {
@@ -1083,7 +1264,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso
} }
// Resolve IP Address // Resolve IP Address
if (!ResolveAddress( Handle, DelayResolve )) if (!ResolveAddress( Handle ))
return NULL; return NULL;
// Create File descriptor // Create File descriptor
@@ -1094,7 +1275,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set Status // Set Status
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -1111,12 +1292,12 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso
} }
// Set status // Set status
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayResolve ) THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle )
{ {
// Socket options // Socket options
struct linger ServerLinger_opt; struct linger ServerLinger_opt;
@@ -1135,7 +1316,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
} }
// Resolve Host & Port Names // Resolve Host & Port Names
if (!ResolveAddress( Handle, DelayResolve )) if (!ResolveAddress( Handle ))
return NULL; return NULL;
// Create socket // Create socket
@@ -1146,7 +1327,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -1159,7 +1340,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; return NULL;
} }
@@ -1174,7 +1355,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Set state
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; 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)", 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) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Close handle
close( Handle->FD ); close( Handle->FD );
Handle->FD = -1; Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true; Handle->AddressFailed = true;
HandleState( Handle, csFailed );
return NULL; 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)", 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) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state // Close handle
close( Handle->FD ); close( Handle->FD );
Handle->FD = -1; Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true; Handle->AddressFailed = true;
HandleState( Handle, csFailed );
return NULL; return NULL;
}; };
@@ -1222,7 +1405,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
} }
// Set state // Set state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -1270,7 +1453,6 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
strcpy( ClientAddress, inet_ntoa(address.sin_addr) ); strcpy( ClientAddress, inet_ntoa(address.sin_addr) );
sprintf( ClientPort, "%d", ntohs(address.sin_port) ); sprintf( ClientPort, "%d", ntohs(address.sin_port) );
// Get end of client list // Get end of client list
RemoteClient = &FirstHandle; RemoteClient = &FirstHandle;
while (*RemoteClient) { while (*RemoteClient) {
@@ -1280,7 +1462,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
// Create Remote Client Handle // Create Remote Client Handle
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD ); sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
*RemoteClient = CreateHandle( ClientName, false ); *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)", 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) ); ProcessName, Name, Handle->Name, strerror(errno) );
return NULL; return NULL;
@@ -1325,7 +1507,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
ProcessName, Name, Handle->Name, Handle->HostName ); ProcessName, Name, Handle->Name, Handle->HostName );
// Update state // Update state
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; 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 // Socket options
int KeepAlive_opt = 1; int KeepAlive_opt = 1; // Enable/disable keep alive
int TCPidle_opt = 5; int TCPidle_opt = 5; // Idle time on socket before sending first keep alive signal
int TCPcnt_opt = 3; int TCPint_opt = 2; // Interval between keep alive signals
int TCPint_opt = 2; 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 // Check state
if (Handle->State == csOpen) { if (Handle->State == csOpen) {
@@ -1350,7 +1533,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
if (Handle->State != csWaitingtoOpen) if (Handle->State != csWaitingtoOpen)
{ {
// Resolve IP Address // Resolve IP Address
if (!ResolveAddress( Handle, DelayResolve )) if (!ResolveAddress( Handle ))
return NULL; return NULL;
// Create File descriptor // Create File descriptor
@@ -1361,7 +1544,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set Status // Set Status
ChangeState( Handle, csFailed ); HandleState( Handle, csFailed );
return NULL; 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) || 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_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_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 // Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)", 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) ); ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set State // Close handle
close( Handle->FD ); close( Handle->FD );
Handle->FD = -1; Handle->FD = -1;
ChangeState( Handle, csFailed );
HandleState( Handle, csFailed );
return NULL; return NULL;
} }
} }
@@ -1399,7 +1584,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
} }
// Set status // Set status
ChangeState( Handle, csOpen ); HandleState( Handle, csOpen );
return Handle; return Handle;
} }
else if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EALREADY)) else if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EALREADY))
@@ -1414,7 +1599,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
} }
// Set status // Set status
ChangeState( Handle, csWaitingtoOpen ); HandleState( Handle, csWaitingtoOpen );
return Handle; return Handle;
} }
else else
@@ -1430,17 +1615,16 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso
// Close socket // Close socket
close( Handle->FD ); close( Handle->FD );
ChangeState( Handle, csFailed ); Handle->FD = -1;
Handle->AddressFailed = true; Handle->AddressFailed = true;
// Reset Handle HandleState( Handle, csFailed );
Handle->FD = -1;
return NULL; return NULL;
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int CSelectableCore::Open( THandle * Handle, bool DelayResolve ) int CSelectableCore::Open( THandle * Handle )
{ {
THandle * NewHandle = NULL; THandle * NewHandle = NULL;
@@ -1467,16 +1651,16 @@ int CSelectableCore::Open( THandle * Handle, bool DelayResolve )
NewHandle = OpenUNIXclientSocket( Handle ); NewHandle = OpenUNIXclientSocket( Handle );
break; break;
case ctUDPserver : case ctUDPserver :
NewHandle = OpenUDPserverSocket( Handle, DelayResolve ); NewHandle = OpenUDPserverSocket( Handle );
break; break;
case ctUDPclient : case ctUDPclient :
NewHandle = OpenUDPclientSocket( Handle, DelayResolve ); NewHandle = OpenUDPclientSocket( Handle );
break; break;
case ctTCPserver : case ctTCPserver :
NewHandle = OpenTCPserverSocket( Handle, DelayResolve ); NewHandle = OpenTCPserverSocket( Handle );
break; break;
case ctTCPclient : case ctTCPclient :
NewHandle = OpenTCPclientSocket( Handle, DelayResolve ); NewHandle = OpenTCPclientSocket( Handle );
break; break;
default: default:
NewHandle = NULL; NewHandle = NULL;
@@ -1532,7 +1716,16 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
} else { } else {
Fail = (close( Handle->FD ))? true : false; 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) // Start timer (for re-open)
if (QuickReopen) if (QuickReopen)
@@ -1616,15 +1809,8 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
break; break;
}; };
// Remove from Select List // Change State
if (!Fail && Selector) { HandleState( Handle, ((Fail)? csFailed : csClosed) );
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -1680,7 +1866,7 @@ bool CSelectableCore::Read( THandle * Handle )
if (Handle->Type == ctTCPremote) { if (Handle->Type == ctTCPremote) {
OpenTCPremoteSocket( Handle ); OpenTCPremoteSocket( Handle );
} else if (Handle->Type == ctTCPclient) { } else if (Handle->Type == ctTCPclient) {
OpenTCPclientSocket( Handle, true ); OpenTCPclientSocket( Handle );
} else if (Handle->Type == ctUNIXremote) { } else if (Handle->Type == ctUNIXremote) {
OpenUNIXremoteSocket( Handle ); OpenUNIXremoteSocket( Handle );
} else if (Handle->Type == ctUNIXclient) { } else if (Handle->Type == ctUNIXclient) {
@@ -1842,7 +2028,7 @@ bool CSelectableCore::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{ {
// Attempt to re-open port // Attempt to re-open port
Open( Handle, true ); Open( Handle );
} }
} }
@@ -1856,7 +2042,7 @@ bool CSelectableCore::Write( THandle * Handle )
if (Handle->Type == ctTCPremote) { if (Handle->Type == ctTCPremote) {
OpenTCPremoteSocket( Handle ); OpenTCPremoteSocket( Handle );
} else if (Handle->Type == ctTCPclient) { } else if (Handle->Type == ctTCPclient) {
OpenTCPclientSocket( Handle, true ); OpenTCPclientSocket( Handle );
} else if (Handle->Type == ctUNIXremote) { } else if (Handle->Type == ctUNIXremote) {
OpenUNIXremoteSocket( Handle ); OpenUNIXremoteSocket( Handle );
} else if (Handle->Type == ctUNIXclient) { } 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 )) else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{ {
// Complete opening process // Complete opening process
Open( Handle, true ); Open( Handle );
// Check if Handle is open // Check if Handle is open
if (Handle->State == csOpenRequest) { if (Handle->State == csPreparing) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Resolving (auto-managed) Handle",
ProcessName, Name, Handle->Name ); ProcessName, Name, Handle->Name );
return 0; return 0;
} }
@@ -2153,16 +2339,14 @@ bool CSelectableCore::Process()
while (Handle) while (Handle)
{ {
// Auto manage handles // Auto manage handles
if ((Handle->State == csOpenRequest)) { if (Handle->State == csPrepared) {
// Resolve then open socket // Proceed to open
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) { Open( Handle );
Open( Handle, false );
}
} }
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 // Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { 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 // Standard C/C++ Libraries
#include <ctype.h> #include <ctype.h>
#include <signal.h>
#include <netdb.h>
// redA Libraries // redA Libraries
#include "FunctionCore.h" #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", 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" }; "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; typedef enum { csNone = 0, csPreparing = 1, csPrepared = 2, csWaitingtoOpen = 3, csOpen = 4, csDataWaiting = 5, csClosed = 6, csFailed = 7 } EConnectState;
const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" }; 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 // Previews
typedef struct SSelectHandle TSelectHandle; typedef struct SSelectHandle TSelectHandle;
typedef struct SHandle THandle; typedef struct SHandle THandle;
typedef struct SResolveReq TResolveReq;
class CSelect; class CSelect;
class CSelectableBare; class CSelectableBare;
class CSelectableCore; class CSelectableCore;
// Callback function for handle events // 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 // List
TSelectHandle * Next = NULL; TSelectHandle * Next = NULL;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// List or Handles for Selectable Function Object // List or Handles for Selectable Function Object
@@ -76,6 +78,7 @@ struct SHandle {
// Description // Description
char * Name = NULL; char * Name = NULL;
EConnectType Type = ctNone; EConnectType Type = ctNone;
CSelectableBare * Function = NULL;
// State // State
int FD = -1; int FD = -1;
@@ -88,7 +91,7 @@ struct SHandle {
long CloseTimeout = 1000; // millisecs of no traffic before closing socket long CloseTimeout = 1000; // millisecs of no traffic before closing socket
// Callback functions // 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 // Type specific parameters
char * Path = NULL; // Port (file)name or Exec path char * Path = NULL; // Port (file)name or Exec path
@@ -103,7 +106,8 @@ struct SHandle {
struct addrinfo * AddressInfo = NULL; // Current selected IP Address struct addrinfo * AddressInfo = NULL; // Current selected IP Address
bool AddressFailed = false; // Indicate failure to connect to address bool AddressFailed = false; // Indicate failure to connect to address
short Queue = 2; // Max waiting connections short Queue = 2; // Max waiting connections
long ResolveDelay = 0; // Delay before resolving hostname via DNS
TResolveReq * ResolveReq = NULL; // DNS resolve request
// Serial Port config // Serial Port config
bool SerialConfig = false; bool SerialConfig = false;
@@ -132,6 +136,16 @@ struct SHandle {
THandle * Parent = NULL; THandle * Parent = NULL;
THandle * Next = 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; CSelect * Selector = NULL;
// Managing File Handles // Managing File Handles
bool RemoveHandle( THandle * Handle ); virtual bool RemoveHandle( THandle * Handle );
bool DestroyHandle( THandle * Handle ); virtual bool DestroyHandle( THandle * Handle );
virtual bool HandleState( THandle * Handle, EConnectState State );
// Get Parameters // Get Parameters
inline int GetFD( const char * HandleName ) { inline int GetFD( const char * HandleName ) {
@@ -201,15 +216,6 @@ protected:
return ((Handle)? Handle->FD : -1); 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 // Mutual Operations
int ReadFromFD( int FD, char * Data, int MaxLen ); int ReadFromFD( int FD, char * Data, int MaxLen );
int WriteToFD( int FD, const char * Data, int Len, bool Force ); int WriteToFD( int FD, const char * Data, int Len, bool Force );
@@ -217,9 +223,6 @@ protected:
// Buffer operations // Buffer operations
virtual bool ProcessInputBuffer( THandle * Handle, bool Force ); virtual bool ProcessInputBuffer( THandle * Handle, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
// Convert string to lower case // Convert string to lower case
inline char * strlcase( char * Str ) { inline char * strlcase( char * Str ) {
for (char * Ch = Str; *Ch; Ch++ ) for (char * Ch = Str; *Ch; Ch++ )
@@ -233,19 +236,17 @@ public:
virtual ~CSelectableBare(); virtual ~CSelectableBare();
// Configuration // Configuration
virtual bool Init( CDataMember * FunctionConfig ) = 0; virtual bool Init( CDataMember * FunctionConfig ) = 0;
// Finding Handles // Finding Handles
inline THandle * GetHandle( const char * HandleName ) inline THandle * GetHandle( const char * HandleName ) {
{
if (!HandleName) return NULL; if (!HandleName) return NULL;
THandle * Handle = FirstHandle; THandle * Handle = FirstHandle;
while ( Handle && strcmp( HandleName, Handle->Name )) while ( Handle && strcmp( HandleName, Handle->Name ))
Handle = Handle->Next; Handle = Handle->Next;
return Handle; return Handle;
} }
inline THandle * GetHandle( int FD ) inline THandle * GetHandle( int FD ) {
{
if (FD < 0) return NULL; if (FD < 0) return NULL;
THandle * Handle = FirstHandle; THandle * Handle = FirstHandle;
while ( Handle && (FD != Handle->FD)) while ( Handle && (FD != Handle->FD))
@@ -254,7 +255,7 @@ public:
} }
// General port parameters // 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 ); virtual CDataMember * GetHandleAddress( THandle * Handle, const char * HandleRef );
bool SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback ); 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 SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen );
bool SetOutBuffer( THandle * Handle, int OutBufSize ); bool SetOutBuffer( THandle * Handle, int OutBufSize );
// Specific port parameters
bool ClearHandle( THandle * Handle );
// FD Operations // 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 Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle ); virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle ); virtual bool Write( THandle * Handle );
// FD operations // 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( const char * HandleName, bool QuickReopen ) { return (Close( GetHandle( HandleName ), QuickReopen )); };
inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); }; inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); };
@@ -294,8 +292,8 @@ public:
}; };
// Function Interface // Function Interface
virtual int Input( const char * ChannelName, const char * Buffer, int BufLen = -1 ); virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process(); virtual bool Process();
}; };
@@ -304,6 +302,8 @@ public:
class CSelectableCore : public CSelectableBare class CSelectableCore : public CSelectableBare
{ {
protected: protected:
struct sigaction ResolveAct;
// Port Operations // Port Operations
THandle * OpenSerialPort( THandle * Handle ); THandle * OpenSerialPort( THandle * Handle );
bool WriteSerialConfig( THandle * Handle ); bool WriteSerialConfig( THandle * Handle );
@@ -318,18 +318,27 @@ protected:
THandle * OpenUNIXremoteSocket( THandle * Handle ); THandle * OpenUNIXremoteSocket( THandle * Handle );
// Socket Operations // Socket Operations
bool ResolveAddress( THandle * Handle, bool DelayResolve ); bool ResolveAddress( THandle * Handle );
THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve ); bool HandleResolve( THandle * Handle );
bool DestroyResolveReq( THandle * Handle, bool DestroyResult );
// Managing File Handles
virtual bool DestroyHandle( THandle * Handle );
THandle * OpenUDPserverSocket( THandle * Handle );
THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort ); THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort );
THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve ); THandle * OpenUDPclientSocket( THandle * Handle );
THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve ); THandle * OpenTCPserverSocket( THandle * Handle );
THandle * OpenTCPremoteSocket( THandle * Handle ); THandle * OpenTCPremoteSocket( THandle * Handle );
THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve ); THandle * OpenTCPclientSocket( THandle * Handle );
// Mutual Operations // Mutual Operations
int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen ); int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen );
int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force ); int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
public: public:
// Life Cycle // Life Cycle
CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE ); CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE );
@@ -339,22 +348,26 @@ public:
virtual bool Init( CDataMember * FunctionConfig ); virtual bool Init( CDataMember * FunctionConfig );
// Specific port parameters // Specific port parameters
bool ClearHandle( THandle * Handle );
bool SetSerialHandle( THandle * Handle, const char * FileName ); bool SetSerialHandle( THandle * Handle, const char * FileName );
bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait ); bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait );
bool SetLinePrinterHandle( THandle * Handle, const char * FileName ); bool SetLinePrinterHandle( THandle * Handle, const char * FileName );
bool SetForkPipeHandle( THandle * Handle, const char * ExecPath ); bool SetForkPipeHandle( THandle * Handle, const char * ExecPath );
bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue ); 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 // FD Operations
virtual int Open( THandle * Handle, bool DelayResolve = false ); virtual int Open( THandle * Handle );
virtual bool Close( THandle * Handle, bool QuickReopen ); virtual bool Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle ); virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle ); virtual bool Write( THandle * Handle );
// Function Interface // Function Interface
int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process(); 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 ); sigemptyset( &TermAct.sa_mask );
TermAct.sa_flags = SA_RESTART; TermAct.sa_flags = SA_RESTART;
sigaction( SIGHUP, &TermAct, 0 ); sigaction( SIGHUP, &TermAct, NULL );
sigaction( SIGINT, &TermAct, 0 ); sigaction( SIGINT, &TermAct, NULL );
sigaction( SIGQUIT, &TermAct, 0 ); sigaction( SIGQUIT, &TermAct, NULL );
sigaction( SIGTERM, &TermAct, 0 ); sigaction( SIGTERM, &TermAct, NULL );
sigaction( SIGTSTP, &TermAct, 0 ); sigaction( SIGTSTP, &TermAct, NULL );
// Signals for immediate termination // Signals for immediate termination
AbortAct.sa_handler = SignalAbort; AbortAct.sa_handler = SignalAbort;
sigemptyset( &AbortAct.sa_mask ); sigemptyset( &AbortAct.sa_mask );
AbortAct.sa_flags = 0; AbortAct.sa_flags = 0;
sigaction( SIGABRT, &AbortAct, 0 ); sigaction( SIGABRT, &AbortAct, NULL );
sigaction( SIGFPE, &AbortAct, 0 ); sigaction( SIGFPE, &AbortAct, NULL );
sigaction( SIGILL, &AbortAct, 0 ); sigaction( SIGILL, &AbortAct, NULL );
sigaction( SIGSEGV, &AbortAct, 0 ); sigaction( SIGSEGV, &AbortAct, NULL );
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -12,6 +12,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <stdio.h>
// redA Libraries // redA Libraries
/* none */ /* none */
@@ -23,19 +24,22 @@ inline void SetInterval( timeval * Time, long MilliSeconds ) {
Time->tv_sec = MilliSeconds / 1000; Time->tv_sec = MilliSeconds / 1000;
Time->tv_usec = (MilliSeconds % 1000) * 1000; Time->tv_usec = (MilliSeconds % 1000) * 1000;
}; };
//---------------------------------------------------------------------------
// Mark start time // Mark start time
inline void SetStartTime( timeval *StartTime ) { inline void SetStartTime( timeval *StartTime ) {
gettimeofday( StartTime, NULL ); gettimeofday( StartTime, NULL );
}; };
//---------------------------------------------------------------------------
// Clear timer // Clear timer
inline void ClearStartTime( timeval * StartTime ) { inline void ClearStartTime( timeval * StartTime ) {
StartTime->tv_sec = 0; StartTime->tv_sec = 0;
StartTime->tv_usec = 0; StartTime->tv_usec = 0;
}; };
//---------------------------------------------------------------------------
// Time passed since start time // Milli-seconds passed since start time
inline long TimePassed( timeval StartTime ) { inline long TimePassed( timeval StartTime ) {
timeval CurrTime; timeval CurrTime;
long Duration; long Duration;
@@ -47,17 +51,54 @@ inline long TimePassed( timeval StartTime ) {
Duration = LONG_MAX; Duration = LONG_MAX;
return Duration; 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 // Time remaining from Start time to given time out
inline long TimeLeft( timeval StartTime, long MilliSeconds ) { inline long TimeLeft( timeval StartTime, long MilliSeconds ) {
return (MilliSeconds - TimePassed(StartTime)); return (MilliSeconds - TimePassed(StartTime));
}; };
//---------------------------------------------------------------------------
// Has give time expired after start time // Has give time expired after start time
inline bool Timeout( timeval StartTime, long MilliSeconds ) { inline bool Timeout( timeval StartTime, long MilliSeconds ) {
return ((TimePassed(StartTime) > MilliSeconds)? true : false); 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_ */ #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 // Remove special char
for (int i=0; i<Len; i++) { 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')))) { (NoCrLf && ((Bytes[i] == '\r') || (Bytes[i] == '\n')))) {
*BufPos = SpecChar; *BufPos = SpecChar;
} }
@@ -75,7 +78,7 @@ char * BytesToHexStr( const char * Bytes, const int Len, const char * Separator,
// Print Hex values of individual bytes // Print Hex values of individual bytes
for (int i=0; i<Len; i++) { 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; BufPos += (First)? 2 : 2+SepLen;
First = false; First = false;
} }
@@ -105,7 +108,7 @@ char * BytesToBinStr( const char * Bytes, const int Len, const char * Separator,
// Print each byte as 8-bit binary // Print each byte as 8-bit binary
for (int i=0; i<Len; i++) { 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] & 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' ); (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; 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 if ((Digit >= 'a') && (Digit <= 'f')) return (Digit - 'a'+10);
else return 0; else return 0;
} }
char * HexStrToBytes( const char * Str, const int Len, const char * Separator, char * OutBuf ); 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 ); char * BinStrToBytes( const char * Str, const int Len, const char * Separator = NULL, char * OutBuf = NULL );
// Search string data // Search string data
char * StrSearch( const char * Haystack, const char * Needle, const int hLen = 0, const int nLen = 0 ); 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; return false;
// Set specific parameters // Set specific parameters
SetInterval( FunctionConfig->GetChInt( "Parameters/PingInterval", 500, true )); SetInterval( Config->GetChInt( "PingInterval", 500, true ));
// Create handle and set reference, if not done // Create handle and set reference, if not done
if (!(Ping = GetHandle( "Ping" ))) if (!(Ping = GetHandle( "Ping" )))