Merge branch 'master' into GISReaderPort
This commit is contained in:
@@ -2,4 +2,5 @@ PROJECT(lib_redAcore)
|
|||||||
|
|
||||||
ADD_LIBRARY(redAcore DateTimeCore.cpp UtilCore.cpp LogCore.cpp SignalCore.cpp DataTreeCore.cpp JSONparseCore.cpp CharBufferCore.cpp
|
ADD_LIBRARY(redAcore DateTimeCore.cpp UtilCore.cpp LogCore.cpp SignalCore.cpp DataTreeCore.cpp JSONparseCore.cpp CharBufferCore.cpp
|
||||||
LiteProtocolCore.cpp ItemBufferCore.cpp EventBufferCore.cpp
|
LiteProtocolCore.cpp ItemBufferCore.cpp EventBufferCore.cpp
|
||||||
ApplicationCore.cpp FunctionCore.cpp FileCore.cpp SelectCore.cpp SelectableCore.cpp WatchdogCore.cpp DeviceCore.cpp )
|
ApplicationCore.cpp FunctionCore.cpp FileCore.cpp SelectCore.cpp SelectableBare.cpp SelectableCore.cpp
|
||||||
|
WatchdogCore.cpp DeviceCore.cpp )
|
||||||
|
|||||||
@@ -171,3 +171,92 @@ char const * GetDateTimeStr( const char * DateSeparator, const char * TimeSepar
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Get current time from real-time clock
|
||||||
|
bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
|
||||||
|
{
|
||||||
|
struct tm CurrentTime;
|
||||||
|
|
||||||
|
// Get current date and time
|
||||||
|
localtime_r( &EpochTime, &CurrentTime );
|
||||||
|
|
||||||
|
// Extract time
|
||||||
|
Hours = CurrentTime.tm_hour;
|
||||||
|
Minutes = CurrentTime.tm_min;
|
||||||
|
Seconds = CurrentTime.tm_sec;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year )
|
||||||
|
{
|
||||||
|
struct tm CurrentDate;
|
||||||
|
|
||||||
|
// Get current date and time
|
||||||
|
localtime_r( &EpochTime, &CurrentDate );
|
||||||
|
|
||||||
|
// Extract date
|
||||||
|
Day = CurrentDate.tm_mday;
|
||||||
|
Month = CurrentDate.tm_mon + 1;
|
||||||
|
Year = CurrentDate.tm_year + 1900;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Get the current date in a string
|
||||||
|
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator )
|
||||||
|
{
|
||||||
|
unsigned char Day;
|
||||||
|
unsigned char Month;
|
||||||
|
unsigned int Year;
|
||||||
|
|
||||||
|
// Get Date
|
||||||
|
ReadDate( EpochTime, Day, Month, Year );
|
||||||
|
|
||||||
|
// Build String
|
||||||
|
sprintf( ReturnStr, "%04d%s%02d%s%02d",
|
||||||
|
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day );
|
||||||
|
|
||||||
|
// Return value
|
||||||
|
return (ReturnStr);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator )
|
||||||
|
{
|
||||||
|
unsigned char Hours;
|
||||||
|
unsigned char Minutes;
|
||||||
|
unsigned char Seconds;
|
||||||
|
|
||||||
|
// Get Date & Time
|
||||||
|
ReadTime( EpochTime, Hours, Minutes, Seconds );
|
||||||
|
|
||||||
|
// Build String
|
||||||
|
sprintf( ReturnStr, "%02d%s%02d%s%02d",
|
||||||
|
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds );
|
||||||
|
|
||||||
|
return (ReturnStr);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator, const char * TimeSeparator )
|
||||||
|
{
|
||||||
|
unsigned char Day;
|
||||||
|
unsigned char Month;
|
||||||
|
unsigned int Year;
|
||||||
|
unsigned char Hours;
|
||||||
|
unsigned char Minutes;
|
||||||
|
unsigned char Seconds;
|
||||||
|
|
||||||
|
// Get Date & Time
|
||||||
|
ReadDate( EpochTime, Day, Month, Year );
|
||||||
|
ReadTime( EpochTime, Hours, Minutes, Seconds );
|
||||||
|
|
||||||
|
// Build String
|
||||||
|
sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d",
|
||||||
|
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day,
|
||||||
|
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds );
|
||||||
|
|
||||||
|
return (ReturnStr);
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,4 +29,13 @@ char const * GetDateTimeStr( const char * DateSeparator = "/", const char * Tim
|
|||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
|
||||||
|
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year );
|
||||||
|
|
||||||
|
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator = "/" );
|
||||||
|
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator = ":" );
|
||||||
|
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" );
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#endif /* REDACORE_DATETIMECORE_H_ */
|
#endif /* REDACORE_DATETIMECORE_H_ */
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
// Standard C/C++ Libraries
|
// Standard C/C++ Libraries
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
// redA Libraries
|
// redA Libraries
|
||||||
#include "JSONparseCore.h"
|
#include "JSONparseCore.h"
|
||||||
@@ -49,10 +48,54 @@ bool CJSONparse::SetBase( CDataMember * Object )
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CJSONparse::WriteToString( const char * BasePath, char * TargetStr, int &MaxLen, const int Indent )
|
||||||
|
{
|
||||||
|
CDataMember * Member;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!DataTree) {
|
||||||
|
Error = true;
|
||||||
|
sprintf( ErrorText, "No Data Tree set" );
|
||||||
|
MaxLen = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare Output
|
||||||
|
if (!TargetStr) {
|
||||||
|
Error = true;
|
||||||
|
sprintf( ErrorText, "Could not write to String" );
|
||||||
|
MaxLen = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OutputStr = TargetStr;
|
||||||
|
OutputMaxLen = MaxLen;
|
||||||
|
OutputPos = 0;
|
||||||
|
Print = JSONstrOutput;
|
||||||
|
|
||||||
|
// Get Root object
|
||||||
|
if (!(Member = DataTree->GetChild( BasePath ))) {
|
||||||
|
Error = true;
|
||||||
|
sprintf( ErrorText, "Invalid root object path" );
|
||||||
|
MaxLen = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print to file
|
||||||
|
if (!PrintObject( Member, Indent ) ||
|
||||||
|
(Print( this, "\n", 1 ) < 0)) {
|
||||||
|
MaxLen = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaxLen = OutputPos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool CJSONparse::WriteToScreen( const char * BasePath, const int Indent )
|
bool CJSONparse::WriteToScreen( const char * BasePath, const int Indent )
|
||||||
{
|
{
|
||||||
// Print to screen
|
// Print to screen
|
||||||
WriteToHandle( BasePath, 1, Indent );
|
WriteToHandle( BasePath, STDOUT_FILENO, Indent );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -100,7 +143,7 @@ bool CJSONparse::WriteToFile( const char * BasePath, const char * FilePath, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC, 660 )) < 0) {
|
if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC, 0660 )) < 0) {
|
||||||
Error = true;
|
Error = true;
|
||||||
sprintf( ErrorText, "Could not open file" );
|
sprintf( ErrorText, "Could not open file" );
|
||||||
return false;
|
return false;
|
||||||
@@ -133,6 +176,7 @@ bool CJSONparse::WriteToHandle( const char * BasePath, const int Handle, const i
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
OutputHandle = Handle;
|
OutputHandle = Handle;
|
||||||
|
Print = JSONfileOutput;
|
||||||
|
|
||||||
// Get Root object
|
// Get Root object
|
||||||
if (!(Member = DataTree->GetChild( BasePath ))) {
|
if (!(Member = DataTree->GetChild( BasePath ))) {
|
||||||
@@ -144,7 +188,7 @@ bool CJSONparse::WriteToHandle( const char * BasePath, const int Handle, const i
|
|||||||
|
|
||||||
// Print to file
|
// Print to file
|
||||||
if (!PrintObject( Member, Indent ) ||
|
if (!PrintObject( Member, Indent ) ||
|
||||||
(write( OutputHandle, "\n", 1 ) < 0)) {
|
(Print( this, "\n", 1 ) < 0)) {
|
||||||
OutputHandle = -1;
|
OutputHandle = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -228,7 +272,7 @@ bool CJSONparse::ReadFromHandle( const char * BasePath, int Handle, bool pRefill
|
|||||||
InputHandle = Handle;
|
InputHandle = Handle;
|
||||||
|
|
||||||
// Load Buffer
|
// Load Buffer
|
||||||
CreateBuffer( 50 );
|
CreateBuffer( 500 );
|
||||||
if (!FillBuffer()) {
|
if (!FillBuffer()) {
|
||||||
Error = true;
|
Error = true;
|
||||||
sprintf( ErrorText, "Could not read from file" );
|
sprintf( ErrorText, "Could not read from file" );
|
||||||
@@ -759,9 +803,10 @@ bool CJSONparse::ParsePrimitive( CDataMember * Member )
|
|||||||
bool CJSONparse::PrintString( char * String, int Len )
|
bool CJSONparse::PrintString( char * String, int Len )
|
||||||
{
|
{
|
||||||
int BytesWritten = 0;
|
int BytesWritten = 0;
|
||||||
|
char TempBuf[7] = "";
|
||||||
|
|
||||||
// Start quote
|
// Start quote
|
||||||
if (write( OutputHandle, "\"", 1 ) < 0)
|
if (Print( this, "\"", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
@@ -774,7 +819,7 @@ bool CJSONparse::PrintString( char * String, int Len )
|
|||||||
BufPos++;
|
BufPos++;
|
||||||
|
|
||||||
// Print Portion
|
// Print Portion
|
||||||
if (write( OutputHandle, Mark, (BufPos-Mark) ) < 0)
|
if (Print( this, Mark, (BufPos-Mark) ) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Handle special chars
|
// Handle special chars
|
||||||
@@ -783,16 +828,17 @@ bool CJSONparse::PrintString( char * String, int Len )
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (*BufPos) {
|
switch (*BufPos) {
|
||||||
case '\b': BytesWritten = write( OutputHandle, "\\b", 2 ); break;
|
case '\b': BytesWritten = Print( this, "\\b", 2 ); break;
|
||||||
case '\f': BytesWritten = write( OutputHandle, "\\f", 2 ); break;
|
case '\f': BytesWritten = Print( this, "\\f", 2 ); break;
|
||||||
case '\n': BytesWritten = write( OutputHandle, "\\n", 2 ); break;
|
case '\n': BytesWritten = Print( this, "\\n", 2 ); break;
|
||||||
case '\r': BytesWritten = write( OutputHandle, "\\r", 2 ); break;
|
case '\r': BytesWritten = Print( this, "\\r", 2 ); break;
|
||||||
case '\t': BytesWritten = write( OutputHandle, "\\t", 2 ); break;
|
case '\t': BytesWritten = Print( this, "\\t", 2 ); break;
|
||||||
case '/': BytesWritten = write( OutputHandle, "\\/", 2 ); break;
|
case '/': BytesWritten = Print( this, "\\/", 2 ); break;
|
||||||
case '\\': BytesWritten = write( OutputHandle, "\\\\", 2 ); break;
|
case '\\': BytesWritten = Print( this, "\\\\", 2 ); break;
|
||||||
case '"': BytesWritten = write( OutputHandle, "\\\"", 2 ); break;
|
case '"': BytesWritten = Print( this, "\\\"", 2 ); break;
|
||||||
default:
|
default:
|
||||||
BytesWritten = dprintf( OutputHandle, "\\u%04X", (unsigned char)*BufPos );
|
BytesWritten = sprintf( TempBuf, "\\u%04X", (unsigned char)*BufPos );
|
||||||
|
Print( this, TempBuf, 6 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (BytesWritten < 0)
|
if (BytesWritten < 0)
|
||||||
@@ -802,7 +848,7 @@ bool CJSONparse::PrintString( char * String, int Len )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// End Quote
|
// End Quote
|
||||||
if (write( OutputHandle, "\"", 1 ) < 0)
|
if (Print( this, "\"", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -817,12 +863,12 @@ bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|||||||
int Count = 0;
|
int Count = 0;
|
||||||
|
|
||||||
// Opening brace
|
// Opening brace
|
||||||
if (write( OutputHandle, "{", 1 ) < 0)
|
if (Print( this, "{", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if empty
|
// Check if empty
|
||||||
if (Object->Len == 0) {
|
if (Object->Len == 0) {
|
||||||
if (write( OutputHandle, "}", 1 ) < 0)
|
if (Print( this, "}", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -841,10 +887,10 @@ bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (First) {
|
if (First) {
|
||||||
First = false;
|
First = false;
|
||||||
if (write( OutputHandle, "\n", 1 ) < 0)
|
if (Print( this, "\n", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
if (Print( this, Spacer, SpacerLen ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,10 +898,10 @@ bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|||||||
if (!PrintString( Member->Name, strlen(Member->Name) ))
|
if (!PrintString( Member->Name, strlen(Member->Name) ))
|
||||||
return false;
|
return false;
|
||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (write( OutputHandle," : ", 3 ) < 0)
|
if (Print( this, " : ", 3 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (write( OutputHandle, ":", 1 ) < 0)
|
if (Print( this, ":", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,24 +910,24 @@ bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|||||||
switch (Member->Type)
|
switch (Member->Type)
|
||||||
{
|
{
|
||||||
case jtNull :
|
case jtNull :
|
||||||
if (write( OutputHandle, "null", 4 ) < 0)
|
if (Print( this, "null", 4 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case jtBool :
|
case jtBool :
|
||||||
if (!strcmp( Member->Value, "0" )) {
|
if (!strcmp( Member->Value, "0" )) {
|
||||||
if (write( OutputHandle, "false", 5 ) < 0)
|
if (Print( this, "false", 5 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (write( OutputHandle, "true", 4 ) < 0)
|
if (Print( this, "true", 4 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case jtInt :
|
case jtInt :
|
||||||
case jtFloat :
|
case jtFloat :
|
||||||
if (write( OutputHandle, Member->Value, Member->Len ) < 0)
|
if (Print( this, Member->Value, Member->Len ) < 0)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -901,11 +947,11 @@ bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!Last) {
|
if (!Last) {
|
||||||
if (write( OutputHandle, ",", 1 ) < 0)
|
if (Print( this, ",", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (write( OutputHandle, "\n", 1 ) < 0)
|
if (Print( this, "\n", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -918,10 +964,10 @@ bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|||||||
|
|
||||||
// Closing brace
|
// Closing brace
|
||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
if (Print( this, Spacer, SpacerLen ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (write( OutputHandle, "}", 1 ) < 0)
|
if (Print( this, "}", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -935,12 +981,12 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
|
|||||||
int Count = 0;
|
int Count = 0;
|
||||||
|
|
||||||
// Opening brace
|
// Opening brace
|
||||||
if (write( OutputHandle, "[", 1 ) < 0)
|
if (Print( this, "[", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if empty
|
// Check if empty
|
||||||
if (Array->Len == 0) {
|
if (Array->Len == 0) {
|
||||||
if (write( OutputHandle, "]", 1 ) < 0)
|
if (Print( this, "]", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -959,10 +1005,10 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
|
|||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (First) {
|
if (First) {
|
||||||
First = false;
|
First = false;
|
||||||
if (write( OutputHandle, "\n", 1 ) < 0)
|
if (Print( this, "\n", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
if (Print( this, Spacer, SpacerLen ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,21 +1016,21 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
|
|||||||
switch (Member->Type)
|
switch (Member->Type)
|
||||||
{
|
{
|
||||||
case jtNull :
|
case jtNull :
|
||||||
if (write( OutputHandle, "null", 4 ) < 0)
|
if (Print( this, "null", 4 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case jtBool :
|
case jtBool :
|
||||||
case jtInt :
|
case jtInt :
|
||||||
case jtFloat :
|
case jtFloat :
|
||||||
if (write( OutputHandle, Member->Value, Member->Len ) < 0)
|
if (Print( this, Member->Value, Member->Len ) < 0)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case jtString :
|
case jtString :
|
||||||
if ((write( OutputHandle, "\"", 1 ) < 0) ||
|
if ((Print( this, "\"", 1 ) < 0) ||
|
||||||
(write( OutputHandle, Member->Value, Member->Len ) < 0) ||
|
(Print( this, Member->Value, Member->Len ) < 0) ||
|
||||||
(write( OutputHandle, "\"", 1 ) < 0))
|
(Print( this, "\"", 1 ) < 0))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -999,11 +1045,11 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!Last) {
|
if (!Last) {
|
||||||
if (write( OutputHandle, ",", 1 ) < 0)
|
if (Print( this, ",", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (write( OutputHandle, "\n", 1 ) < 0)
|
if (Print( this, "\n", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1016,12 +1062,11 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
|
|||||||
|
|
||||||
// Closing brace
|
// Closing brace
|
||||||
if (Indent) {
|
if (Indent) {
|
||||||
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
if (Print( this, Spacer, SpacerLen ) < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (write( OutputHandle, "]", 1 ) < 0)
|
if (Print( this, "]", 1 ) < 0)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
// Standard C/C++ Libraries
|
// Standard C/C++ Libraries
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
// redA Libraries
|
// redA Libraries
|
||||||
#include "DataTreeCore.h"
|
#include "DataTreeCore.h"
|
||||||
@@ -18,14 +19,26 @@
|
|||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Pointer template for File/String Output functions
|
||||||
|
class CJSONparse;
|
||||||
|
inline ssize_t JSONstrOutput( CJSONparse * JSONparse, const char * Data, size_t Len );
|
||||||
|
inline ssize_t JSONfileOutput( CJSONparse * JSONparse, const char * Data, size_t Len );
|
||||||
|
|
||||||
|
typedef ssize_t (*FOutput)( CJSONparse * JSONparse, const char * Data, size_t Len );
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
class CJSONparse
|
class CJSONparse
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
CDataMember * DataTree = NULL;
|
CDataMember * DataTree = NULL;
|
||||||
|
|
||||||
// File operation
|
// File operation
|
||||||
int InputHandle = -1;
|
int InputHandle = -1;
|
||||||
int OutputHandle = -1;
|
int OutputHandle = -1;
|
||||||
|
char * OutputStr = NULL;
|
||||||
|
size_t OutputMaxLen = 0;
|
||||||
|
size_t OutputPos = 0;
|
||||||
|
|
||||||
CShiftBuffer * Buffer = NULL;
|
CShiftBuffer * Buffer = NULL;
|
||||||
|
|
||||||
@@ -37,6 +50,7 @@ private:
|
|||||||
bool RefillBuffer = false;
|
bool RefillBuffer = false;
|
||||||
|
|
||||||
// Printing Operation
|
// Printing Operation
|
||||||
|
FOutput Print = NULL;
|
||||||
char Spacer[100] = "";
|
char Spacer[100] = "";
|
||||||
int SpacerLen = 0;
|
int SpacerLen = 0;
|
||||||
|
|
||||||
@@ -77,12 +91,33 @@ public:
|
|||||||
bool ReadFromFile( const char * BasePath, const char * FilePath );
|
bool ReadFromFile( const char * BasePath, const char * FilePath );
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
|
bool WriteToString( const char * BasePath, char * TargetStr, int &MaxLen, const int Indent = 0 );
|
||||||
bool WriteToHandle( const char * BasePath, const int Handle, const int Indent = 2 );
|
bool WriteToHandle( const char * BasePath, const int Handle, const int Indent = 2 );
|
||||||
bool WriteToScreen( const char * BasePath, const int Indent = 2 );
|
bool WriteToScreen( const char * BasePath, const int Indent = 2 );
|
||||||
bool WriteToFile( const char * BasePath, const char * Path, const char * FileName, const int Indent = 2 );
|
bool WriteToFile( const char * BasePath, const char * Path, const char * FileName, const int Indent = 2 );
|
||||||
bool WriteToFile( const char * BasePath, const char * FilePath, const int Indent = 2 );
|
bool WriteToFile( const char * BasePath, const char * FilePath, const int Indent = 2 );
|
||||||
|
|
||||||
const char * GetError() { return ((Error)? ErrorText : "Success"); };
|
const char * GetError() { return ((Error)? ErrorText : "Success"); };
|
||||||
|
|
||||||
|
friend inline ssize_t JSONstrOutput( CJSONparse * JSONparse, const char * Data, size_t Len );
|
||||||
|
friend inline ssize_t JSONfileOutput( CJSONparse * JSONparse, const char * Data, size_t Len );
|
||||||
};
|
};
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline ssize_t JSONstrOutput( CJSONparse * JSONparse, const char * Data, size_t Len )
|
||||||
|
{
|
||||||
|
if (JSONparse->OutputPos + Len > JSONparse->OutputMaxLen) return -1;
|
||||||
|
memcpy( &JSONparse->OutputStr[JSONparse->OutputPos], Data, Len );
|
||||||
|
JSONparse->OutputPos += Len;
|
||||||
|
JSONparse->OutputStr[JSONparse->OutputPos] = 0;
|
||||||
|
return Len;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline ssize_t JSONfileOutput( CJSONparse * JSONparse, const char * Data, size_t Len )
|
||||||
|
{
|
||||||
|
return write( JSONparse->OutputHandle, Data, Len );
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#endif /* REDACORE_JSONPARSECORE_H_ */
|
#endif /* REDACORE_JSONPARSECORE_H_ */
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ void CSelect::Clear()
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
// Add Select File Descriptor
|
// Add Select File Descriptor
|
||||||
void CSelect::Add( int FD, bool Read, bool Write, THandle * Handle, CSelectableCore * Function )
|
void CSelect::Add( int FD, bool Read, bool Write, THandle * Handle, CSelectableBare * Function )
|
||||||
{
|
{
|
||||||
TSelectHandle ** SelectHandle = NULL;
|
TSelectHandle ** SelectHandle = NULL;
|
||||||
|
|
||||||
|
|||||||
960
SelectableBare.cpp
Normal file
960
SelectableBare.cpp
Normal file
@@ -0,0 +1,960 @@
|
|||||||
|
/*
|
||||||
|
* SelectableBare.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 2019
|
||||||
|
* Author: wentzelc
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Standard C/C++ Libraries
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
// redA Libraries
|
||||||
|
#include "ApplicationCore.h"
|
||||||
|
#include "SelectableCore.h"
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Global Vars
|
||||||
|
extern char * ProcessName;
|
||||||
|
extern CApplication * Application;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CSelectableBare::CSelectableBare( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
|
||||||
|
{
|
||||||
|
// Quick access
|
||||||
|
Selector = Application->Selector;
|
||||||
|
|
||||||
|
// Handles
|
||||||
|
FirstHandle = NULL;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CSelectableBare::~CSelectableBare()
|
||||||
|
{
|
||||||
|
THandle * NextHandle = NULL;
|
||||||
|
|
||||||
|
// Destroy File Handles
|
||||||
|
while (FirstHandle)
|
||||||
|
{
|
||||||
|
// Close handle if open
|
||||||
|
if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) {
|
||||||
|
Close( FirstHandle, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
NextHandle = FirstHandle->Next;
|
||||||
|
DestroyHandle( FirstHandle );
|
||||||
|
FirstHandle = NextHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CDataMember * CSelectableBare::GetHandleAddress( THandle * Handle, const char * HandleRef )
|
||||||
|
{
|
||||||
|
CDataMember * AddressDef = NULL;
|
||||||
|
char NamePath[100];
|
||||||
|
char * Address;
|
||||||
|
|
||||||
|
// Handle renamed?
|
||||||
|
sprintf( NamePath, "Application/Addresses/Rename/%s", HandleRef );
|
||||||
|
if (!(Address = (char*)Application->Config->GetChStr( NamePath, NULL, false ))) {
|
||||||
|
Address = (char*)HandleRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get address def
|
||||||
|
if ((AddressDef = Application->AddressList->GetChild( Address ))) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Use address '%s' ('%s')",
|
||||||
|
ProcessName, Name, Handle->Name, Address, HandleRef );
|
||||||
|
}
|
||||||
|
return AddressDef;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateChannel )
|
||||||
|
{
|
||||||
|
THandle ** Handle = NULL;
|
||||||
|
|
||||||
|
// Find Handle by Name or get end of list
|
||||||
|
Handle = &FirstHandle;
|
||||||
|
while ( *Handle && strcmp( HandleName, (*Handle)->Name ))
|
||||||
|
Handle = &((*Handle)->Next);
|
||||||
|
|
||||||
|
// Create if necessary
|
||||||
|
if (!*Handle)
|
||||||
|
{
|
||||||
|
// Create File handle at end of list
|
||||||
|
*Handle = (THandle*)calloc( 1, sizeof(THandle) );
|
||||||
|
|
||||||
|
// Set name
|
||||||
|
if (HandleName) {
|
||||||
|
(*Handle)->Name = (char*)malloc( strlen(HandleName)+1 );
|
||||||
|
strcpy( (*Handle)->Name, HandleName );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set File Descriptor
|
||||||
|
(*Handle)->FD = -1;
|
||||||
|
|
||||||
|
// Log event
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created",
|
||||||
|
ProcessName, Name, HandleName );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Matching Channel
|
||||||
|
if (CreateChannel) {
|
||||||
|
(*Handle)->Channel = AddChannel( HandleName );
|
||||||
|
}
|
||||||
|
|
||||||
|
return *Handle;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::RemoveHandle( THandle * Handle )
|
||||||
|
{
|
||||||
|
THandle ** HandlePtr = NULL;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!Handle || (Handle->State == csOpen) || (Handle->State == csWaitingtoOpen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find in List
|
||||||
|
HandlePtr = &FirstHandle;
|
||||||
|
while (*HandlePtr && (*HandlePtr != Handle)) {
|
||||||
|
HandlePtr = &((*HandlePtr)->Next);
|
||||||
|
}
|
||||||
|
// Remove from list if found
|
||||||
|
if (*HandlePtr) {
|
||||||
|
*HandlePtr = (*HandlePtr)->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log event
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Removed",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Destroy Child handle
|
||||||
|
DestroyHandle( Handle );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::DestroyHandle( THandle * Handle )
|
||||||
|
{
|
||||||
|
// Validate Handle
|
||||||
|
if (!Handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 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->AddressInfo)
|
||||||
|
freeaddrinfo( Handle->AddressList );
|
||||||
|
|
||||||
|
// Destroy Buffers
|
||||||
|
if (Handle->InBuffer)
|
||||||
|
delete Handle->InBuffer;
|
||||||
|
if (Handle->OutBuffer)
|
||||||
|
delete Handle->OutBuffer;
|
||||||
|
|
||||||
|
// Clear Input Markers
|
||||||
|
if (Handle->InMarker)
|
||||||
|
free( Handle->InMarker );
|
||||||
|
|
||||||
|
// Destroy Pointer
|
||||||
|
free( Handle );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::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 CSelectableBare::SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback )
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (!Handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set callback
|
||||||
|
Handle->StateCallback[ (int)pState ] = pCallback;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::SetAutoManage( THandle * Handle, bool AutoManage, bool Persistent, int ReopenDelay, int CloseTimeout )
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (!Handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set params
|
||||||
|
Handle->AutoManage = AutoManage;
|
||||||
|
Handle->Persistent = Persistent;
|
||||||
|
Handle->ReopenDelay = ReopenDelay;
|
||||||
|
Handle->CloseTimeout = CloseTimeout;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen )
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (!Handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input Buffer
|
||||||
|
if (Handle->InBuffer) {
|
||||||
|
delete Handle->InBuffer;
|
||||||
|
Handle->InBuffer = NULL;
|
||||||
|
}
|
||||||
|
if (InBufSize) {
|
||||||
|
Handle->InBuffer = (CRollingBuffer*) new CRollingBuffer( InBufSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Input Timeout
|
||||||
|
Handle->InTimeout = InTimeout;
|
||||||
|
|
||||||
|
// Set Input Markers
|
||||||
|
if (InMarkerLen && InMarker) {
|
||||||
|
Handle->InMarkerLen = InMarkerLen;
|
||||||
|
Handle->InMarker = (char *)malloc( InMarkerLen+1 );
|
||||||
|
memcpy( Handle->InMarker, InMarker, InMarkerLen );
|
||||||
|
Handle->InMarker[InMarkerLen] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::SetOutBuffer( THandle * Handle, int OutBufSize )
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (!Handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output Buffer
|
||||||
|
if (Handle->OutBuffer) {
|
||||||
|
delete Handle->OutBuffer;
|
||||||
|
Handle->OutBuffer = NULL;
|
||||||
|
}
|
||||||
|
if (OutBufSize) {
|
||||||
|
Handle->OutBuffer = (CRollingBuffer*) new CRollingBuffer( OutBufSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
|
||||||
|
{
|
||||||
|
int Pos = 0;
|
||||||
|
int Len = 0;
|
||||||
|
char * Data = NULL;
|
||||||
|
|
||||||
|
// Check if buffered data
|
||||||
|
if (!Handle || !Handle->InBuffer || !Handle->InBuffer->Len()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if forced processed
|
||||||
|
if (Force || !Handle->InMarkerLen)
|
||||||
|
{
|
||||||
|
// Show Packet
|
||||||
|
Len = Handle->InBuffer->Peek( &Data );
|
||||||
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - IN-T:",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Write buffer to Outputs
|
||||||
|
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
|
||||||
|
Output( Handle->Parent->Channel, Data, Len );
|
||||||
|
} else {
|
||||||
|
Output( Handle->Channel, Data, Len );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear processed bytes from buffer
|
||||||
|
Handle->InBuffer->Clear( Len );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - IN:",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Search for end of packet marker
|
||||||
|
while (Handle->InBuffer->FindStr( Handle->InMarker, Handle->InMarkerLen, Pos ))
|
||||||
|
{
|
||||||
|
// Show Packet
|
||||||
|
Len = Handle->InBuffer->Peek( &Data, 0, Pos+Handle->InMarkerLen );
|
||||||
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - IN-M:",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Write buffer to Outputs
|
||||||
|
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
|
||||||
|
Output( Handle->Parent->Channel, Data, Len );
|
||||||
|
} else {
|
||||||
|
Output( Handle->Channel, Data, Len );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear processed bytes from buffer
|
||||||
|
Handle->InBuffer->Clear( Len );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
|
||||||
|
{
|
||||||
|
THandle * NewHandle = NULL;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!Handle || (Handle->Type == ctNone)) {
|
||||||
|
return -1;
|
||||||
|
} else if (Handle->State == csOpen) {
|
||||||
|
return Handle->FD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if port exits
|
||||||
|
if (access( Handle->Path, F_OK ) != 0)
|
||||||
|
{
|
||||||
|
// Log event
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Path not found [%s]",
|
||||||
|
ProcessName, Name, Handle->Name, Handle->Path );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open Port
|
||||||
|
Handle->FD = open( Handle->Path, O_RDWR );
|
||||||
|
if (Handle->FD == -1)
|
||||||
|
{
|
||||||
|
// Log event
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Could not open Path [%s]",
|
||||||
|
ProcessName, Name, Handle->Name, Handle->Path );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log Event
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Path opened [%s]",
|
||||||
|
ProcessName, Name, Handle->Name, Handle->Path );
|
||||||
|
|
||||||
|
// Add to Select Lists
|
||||||
|
if (Selector) {
|
||||||
|
Selector->Add( Handle->FD, true, false, Handle, this );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set state
|
||||||
|
ChangeState( Handle, csOpen );
|
||||||
|
|
||||||
|
// Set timer (for re-open or auto-close)
|
||||||
|
SetStartTime( &Handle->LastAction );
|
||||||
|
return (NewHandle)? NewHandle->FD : -1;
|
||||||
|
};
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Delete socket
|
||||||
|
bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
|
||||||
|
{
|
||||||
|
bool Fail;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!Handle || (Handle->FD == -1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Close Handle
|
||||||
|
Fail = (close( Handle->FD ))? true : false;
|
||||||
|
ChangeState( Handle, ((Fail)? csFailed : csClosed) );
|
||||||
|
|
||||||
|
// Start timer (for re-open)
|
||||||
|
if (QuickReopen)
|
||||||
|
ClearStartTime( &(Handle->LastAction) );
|
||||||
|
else
|
||||||
|
SetStartTime( &(Handle->LastAction) );
|
||||||
|
|
||||||
|
// Show action
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s",
|
||||||
|
ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") );
|
||||||
|
|
||||||
|
// Remove from Select List
|
||||||
|
if (!Fail && Selector) {
|
||||||
|
if (Handle->Type != ctUDPremote) {
|
||||||
|
Selector->Remove( Handle->FD, true, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset FD
|
||||||
|
Handle->FD = ((Fail)? Handle->FD : -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Device Interface
|
||||||
|
bool CSelectableBare::Read( THandle * Handle )
|
||||||
|
{
|
||||||
|
int BytesRead = 0;
|
||||||
|
int BytesWaiting = -1;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!Handle || (Handle->State == csNone) || (Handle->State == csFailed) || (Handle->State == csClosed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log Read Event
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Read Event",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Check if socket ready (non-block open in progress)
|
||||||
|
if (Handle->State == csWaitingtoOpen)
|
||||||
|
{
|
||||||
|
Open( Handle );
|
||||||
|
|
||||||
|
// Reset Timer (for auto-close)
|
||||||
|
SetStartTime( &(Handle->LastAction) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if anything to read
|
||||||
|
ioctl( Handle->FD, FIONREAD, &BytesWaiting );
|
||||||
|
|
||||||
|
// Error on port
|
||||||
|
if (BytesWaiting < 0)
|
||||||
|
{
|
||||||
|
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Data waiting error (%s)",
|
||||||
|
ProcessName, Name, Handle->Name, strerror(errno) );
|
||||||
|
|
||||||
|
// Close Handle
|
||||||
|
Close( Handle, false );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (Handle->State != csOpen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read File directly into buffer
|
||||||
|
if (Handle->InBuffer)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD, BytesWaiting );
|
||||||
|
|
||||||
|
// Report failure
|
||||||
|
if (errno) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Error reading data [%d/%d] (%s)",
|
||||||
|
ProcessName, Name, Handle->Name, -BytesRead, BytesWaiting, strerror(errno) );
|
||||||
|
}
|
||||||
|
else if (BytesRead < BytesWaiting) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Incomplete data read [%d/%d]",
|
||||||
|
ProcessName, Name, Handle->Name, BytesRead, BytesWaiting );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BytesRead != 0) {
|
||||||
|
// Process Buffer
|
||||||
|
ProcessInputBuffer( Handle, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset timer
|
||||||
|
SetStartTime( &(Handle->InStart) );
|
||||||
|
|
||||||
|
return (bool)BytesRead;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::Write( THandle * Handle )
|
||||||
|
{
|
||||||
|
int Len = 0;
|
||||||
|
char * Data = NULL;
|
||||||
|
int BytesWritten = 0;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!Handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Is Handle open?
|
||||||
|
if ((Handle->State == csNone) || (Handle->State == csFailed) || (Handle->State == csClosed))
|
||||||
|
{
|
||||||
|
// May it be opened?
|
||||||
|
if (!Handle->AutoManage)
|
||||||
|
{
|
||||||
|
// Must be opened manually
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
|
||||||
|
{
|
||||||
|
// Attempt to re-open port
|
||||||
|
Open( Handle, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log Ready for Write Event
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Write Event",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
if (Handle->State == csWaitingtoOpen)
|
||||||
|
{
|
||||||
|
// Complete socket open process
|
||||||
|
Open( Handle );
|
||||||
|
|
||||||
|
// Reset Timer (for auto-close)
|
||||||
|
SetStartTime( &(Handle->LastAction) );
|
||||||
|
|
||||||
|
// Remove from set for select write
|
||||||
|
if (Selector) {
|
||||||
|
Selector->Remove( Handle->FD, false, true );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (Handle->State == csOpen)
|
||||||
|
{
|
||||||
|
if (Handle->OutBuffer)
|
||||||
|
{
|
||||||
|
// Write directly to handle / socket
|
||||||
|
errno = 0;
|
||||||
|
BytesWritten = Handle->OutBuffer->WriteToFD( Handle->FD );
|
||||||
|
|
||||||
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - OUT:",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Report failure
|
||||||
|
if (errno) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Error sending data [%d/%d] (%s)",
|
||||||
|
ProcessName, Name, Handle->Name, -BytesWritten, Len, strerror(errno) );
|
||||||
|
}
|
||||||
|
else if (BytesWritten < Len) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Incomplete data sent [%d/%d]",
|
||||||
|
ProcessName, Name, Handle->Name, BytesWritten, Len );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BytesWritten != 0)
|
||||||
|
{
|
||||||
|
// Update Buffer
|
||||||
|
Handle->OutBuffer->Clear( (BytesWritten > 0)? BytesWritten : -BytesWritten ); // negative value reported if error occurred
|
||||||
|
|
||||||
|
// Check if Buffer empty
|
||||||
|
if (!Handle->OutBuffer->Len()) {
|
||||||
|
// Remove from Select Write list
|
||||||
|
if (Selector) {
|
||||||
|
Selector->Remove( Handle->FD, false, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset timeout
|
||||||
|
SetStartTime( &(Handle->LastAction) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No Output buffer to write from, so remove from Write list
|
||||||
|
if (Selector) {
|
||||||
|
Selector->Remove( Handle->FD, false, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int CSelectableBare::ReadFromFD( int FD, char * Data, int MaxLen )
|
||||||
|
{
|
||||||
|
int BytesRead = 0;
|
||||||
|
int TotalRead = 0;
|
||||||
|
int DataRemain = MaxLen;
|
||||||
|
bool Error = false;
|
||||||
|
|
||||||
|
// Check if buffer created
|
||||||
|
if ((FD == -1) || (MaxLen < 1)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Data into buffer
|
||||||
|
while (DataRemain)
|
||||||
|
{
|
||||||
|
// Read from file descriptor
|
||||||
|
BytesRead = read( FD, &Data[TotalRead], DataRemain );
|
||||||
|
if ((BytesRead < 0)) {
|
||||||
|
Error = true;
|
||||||
|
errno = (!BytesRead)? 0 : errno; // No error if no bytes written
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Data Pointers
|
||||||
|
TotalRead += BytesRead;
|
||||||
|
DataRemain -= BytesRead;
|
||||||
|
|
||||||
|
if (DataRemain) {
|
||||||
|
usleep( 500 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Error)? -TotalRead : TotalRead; // Report negative total on error
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int CSelectableBare::WriteToFD( int FD, const char * Data, int Len, bool Force )
|
||||||
|
{
|
||||||
|
int BytesWritten = 0;
|
||||||
|
int TotalWritten = 0;
|
||||||
|
int DataRemain = (Len != -1)? Len : (Data)? strlen(Data) : 0;
|
||||||
|
bool Error = false;
|
||||||
|
|
||||||
|
// Check if buffer created
|
||||||
|
if ((FD == -1) || !DataRemain) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Data into buffer
|
||||||
|
while (DataRemain)
|
||||||
|
{
|
||||||
|
// Read from file descriptor
|
||||||
|
BytesWritten = write( FD, &Data[TotalWritten], DataRemain );
|
||||||
|
if ((BytesWritten <= 0) && (!Force || (errno != EAGAIN))) {
|
||||||
|
Error = true;
|
||||||
|
errno = (!BytesWritten)? 0 : errno; // No error if no bytes written
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Data Pointers
|
||||||
|
TotalWritten += BytesWritten;
|
||||||
|
DataRemain -= BytesWritten;
|
||||||
|
|
||||||
|
if (DataRemain) {
|
||||||
|
usleep( 500 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Error)? -TotalWritten : TotalWritten; // Report negative total on error
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len )
|
||||||
|
{
|
||||||
|
TChannel * Channel = NULL;
|
||||||
|
THandle * Handle = NULL;
|
||||||
|
int HandleCount = 0;
|
||||||
|
int TempWritten = 0;
|
||||||
|
int BytesWritten = 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' - Input rejected, Channel not found",
|
||||||
|
ProcessName, Name, ChannelName );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (!Channel->InputEnabled) {
|
||||||
|
// Channel disabled
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled",
|
||||||
|
ProcessName, Name, ChannelName );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log event
|
||||||
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
|
||||||
|
ProcessName, Name, ChannelName );
|
||||||
|
|
||||||
|
// Find Linked handle
|
||||||
|
Handle = FirstHandle;
|
||||||
|
while( Handle )
|
||||||
|
{
|
||||||
|
if (Handle->Channel && !strcasecmp( ChannelName, Handle->Channel->Name ))
|
||||||
|
{
|
||||||
|
// Input to Handle
|
||||||
|
TempWritten = OutputHandle( Handle, Data, Len );
|
||||||
|
BytesWritten = (TempWritten > BytesWritten)? TempWritten : BytesWritten;
|
||||||
|
HandleCount++;
|
||||||
|
}
|
||||||
|
Handle = Handle->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HandleCount) {
|
||||||
|
// Handle not found
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles found",
|
||||||
|
ProcessName, Name, ChannelName );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BytesWritten;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int CSelectableBare::OutputHandle( THandle * Handle, const char * Data, int Len )
|
||||||
|
{
|
||||||
|
int BytesWritten = 0;
|
||||||
|
int DataLen = (Len != -1)? Len : (Data)? strlen(Data) : 0;
|
||||||
|
|
||||||
|
if ((Handle->State != csOpen))
|
||||||
|
{
|
||||||
|
// Check if auto-managed handle
|
||||||
|
if (!Handle->AutoManage)
|
||||||
|
{
|
||||||
|
// Handle is not open or auto-managed
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Handle not Open (not auto-managed)",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
|
||||||
|
{
|
||||||
|
// Complete opening process
|
||||||
|
Open( Handle, true );
|
||||||
|
|
||||||
|
// Check if Handle is open
|
||||||
|
if (Handle->State == csOpenRequest) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (Handle->State == csWaitingtoOpen) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Waiting to open (auto-managed) Handle",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (Handle->State != csOpen) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, (auto-managed) Handle failed to Open",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Retry (auto-managed) Handle re-open in %d ms",
|
||||||
|
ProcessName, Name, Handle->Name, TimeLeft( Handle->LastAction, Handle->ReopenDelay) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check packet length
|
||||||
|
if (Len == -1) {
|
||||||
|
Len = strlen( Data );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide where to put data
|
||||||
|
if (Handle->OutBuffer)
|
||||||
|
{
|
||||||
|
// Write to buffer
|
||||||
|
BytesWritten = Handle->OutBuffer->Push( true, Data, Len );
|
||||||
|
|
||||||
|
// Add to select write list
|
||||||
|
if (BytesWritten && Selector) {
|
||||||
|
Selector->Add( Handle->FD, false, true, Handle, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write directly to handle / socket
|
||||||
|
errno = 0;
|
||||||
|
BytesWritten = WriteToFD( Handle->FD, Data, Len, true );
|
||||||
|
|
||||||
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - OUT:",
|
||||||
|
ProcessName, Name, Handle->Name );
|
||||||
|
|
||||||
|
// Report failure
|
||||||
|
if (errno) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Error sending data [%d/%d] (%s)",
|
||||||
|
ProcessName, Name, Handle->Name, -BytesWritten, DataLen, strerror(errno) );
|
||||||
|
}
|
||||||
|
else if (BytesWritten < DataLen) {
|
||||||
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Incomplete data sent [%d/%d]",
|
||||||
|
ProcessName, Name, Handle->Name, BytesWritten, DataLen );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BytesWritten != 0) {
|
||||||
|
// Reset timeout
|
||||||
|
SetStartTime( &(Handle->LastAction) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BytesWritten;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::Process()
|
||||||
|
{
|
||||||
|
THandle * Handle = NULL;
|
||||||
|
|
||||||
|
// Check all handles
|
||||||
|
Handle = FirstHandle;
|
||||||
|
while (Handle)
|
||||||
|
{
|
||||||
|
// Auto manage handles
|
||||||
|
if ((Handle->State == csOpenRequest))
|
||||||
|
{
|
||||||
|
// Resolve then open socket
|
||||||
|
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
|
||||||
|
Open( Handle, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) )
|
||||||
|
{
|
||||||
|
// Try to re-open port after delay
|
||||||
|
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) {
|
||||||
|
Open( Handle, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Input buffers
|
||||||
|
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0))
|
||||||
|
{
|
||||||
|
// Check duration since last PortIn
|
||||||
|
if (Timeout( Handle->InStart, Handle->InTimeout ))
|
||||||
|
{
|
||||||
|
// Process Input
|
||||||
|
ProcessInputBuffer( Handle, true );
|
||||||
|
|
||||||
|
// Reset timer
|
||||||
|
ClearStartTime( &(Handle->InStart) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for auto close (but not on servers)
|
||||||
|
if ((Handle->State == csOpen) && (Handle->Type != ctTCPserver) && (Handle->Type != ctUNIXserver) && Handle->AutoManage && !Handle->Persistent)
|
||||||
|
{
|
||||||
|
// Close port after timeout
|
||||||
|
if (Timeout( Handle->LastAction, Handle->CloseTimeout )) {
|
||||||
|
Close( Handle, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle = Handle->Next;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CSelectableBare::BuildArgs( const char * ExecPath, int &Count, char * Args[] )
|
||||||
|
{
|
||||||
|
bool ParamStarted = false;
|
||||||
|
bool OpenQuotes = false;
|
||||||
|
char * MatchPos = NULL;
|
||||||
|
char * StartPos = NULL;
|
||||||
|
int Len;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (!ExecPath || !*ExecPath) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split params
|
||||||
|
MatchPos = (char*)ExecPath;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Look for whitespace
|
||||||
|
if (!ParamStarted)
|
||||||
|
{
|
||||||
|
// Quotes starts quoted parameter
|
||||||
|
if (*MatchPos == '"') {
|
||||||
|
ParamStarted = true;
|
||||||
|
OpenQuotes = true;
|
||||||
|
StartPos = MatchPos+1; // Skip starting quote
|
||||||
|
}
|
||||||
|
// Non-whitespace starts normal parameter
|
||||||
|
else if ((*MatchPos != ' ') && (*MatchPos != 0)) {
|
||||||
|
ParamStarted = true;
|
||||||
|
StartPos = MatchPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (OpenQuotes)
|
||||||
|
{
|
||||||
|
// Another quote ends parameter
|
||||||
|
if (*MatchPos == '"') {
|
||||||
|
Len = MatchPos-StartPos-1; // Skip end quote
|
||||||
|
Args[Count] = (char*)malloc( Len+1 );
|
||||||
|
strncpy( Args[Count], StartPos, Len );
|
||||||
|
Args[Count][Len] = 0;
|
||||||
|
Count++;
|
||||||
|
ParamStarted = false;
|
||||||
|
OpenQuotes = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Whitespace ends parameter
|
||||||
|
if ((*MatchPos == ' ') || (*MatchPos == 0)) {
|
||||||
|
Len = MatchPos-StartPos;
|
||||||
|
Args[Count] = (char*)malloc( Len+1 );
|
||||||
|
strncpy( Args[Count], StartPos, Len );
|
||||||
|
Args[Count][Len] = 0;
|
||||||
|
Count++;
|
||||||
|
ParamStarted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Next char, unless NULL
|
||||||
|
if (*MatchPos)
|
||||||
|
MatchPos++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all parameters closed
|
||||||
|
if (ParamStarted) {
|
||||||
|
Count = 0;
|
||||||
|
Args[0] = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set last Param to NULL
|
||||||
|
Args[Count] = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ CFunctionCore * NewSelectableCore( const char * Name ) {
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
|
CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CSelectableBare( pName, pType )
|
||||||
{
|
{
|
||||||
// Quick access
|
// Quick access
|
||||||
Selector = Application->Selector;
|
Selector = Application->Selector;
|
||||||
@@ -243,127 +243,6 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig )
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CDataMember * CSelectableCore::GetHandleAddress( THandle * Handle, const char * HandleRef )
|
|
||||||
{
|
|
||||||
CDataMember * AddressDef = NULL;
|
|
||||||
char NamePath[100];
|
|
||||||
char * Address;
|
|
||||||
|
|
||||||
// Handle renamed?
|
|
||||||
sprintf( NamePath, "Application/Addresses/Rename/%s", HandleRef );
|
|
||||||
if (!(Address = (char*)Application->Config->GetChStr( NamePath, NULL, false ))) {
|
|
||||||
Address = (char*)HandleRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get address def
|
|
||||||
if ((AddressDef = Application->AddressList->GetChild( Address ))) {
|
|
||||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Use address '%s' ('%s')",
|
|
||||||
ProcessName, Name, Handle->Name, Address, HandleRef );
|
|
||||||
}
|
|
||||||
return AddressDef;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
THandle * CSelectableCore::CreateHandle( const char * HandleName, bool CreateChannel )
|
|
||||||
{
|
|
||||||
THandle ** Handle = NULL;
|
|
||||||
|
|
||||||
// Find Handle by Name or get end of list
|
|
||||||
Handle = &FirstHandle;
|
|
||||||
while ( *Handle && strcmp( HandleName, (*Handle)->Name ))
|
|
||||||
Handle = &((*Handle)->Next);
|
|
||||||
|
|
||||||
// Create if necessary
|
|
||||||
if (!*Handle)
|
|
||||||
{
|
|
||||||
// Create File handle at end of list
|
|
||||||
*Handle = (THandle*)calloc( 1, sizeof(THandle) );
|
|
||||||
|
|
||||||
// Set name
|
|
||||||
if (HandleName) {
|
|
||||||
(*Handle)->Name = strdup( HandleName );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set File Descriptor
|
|
||||||
(*Handle)->FD = -1;
|
|
||||||
|
|
||||||
// Log event
|
|
||||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created",
|
|
||||||
ProcessName, Name, HandleName );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Matching Channel
|
|
||||||
if (CreateChannel) {
|
|
||||||
(*Handle)->Channel = AddChannel( HandleName );
|
|
||||||
}
|
|
||||||
|
|
||||||
return *Handle;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CSelectableCore::RemoveHandle( THandle * Handle )
|
|
||||||
{
|
|
||||||
THandle ** HandlePtr = NULL;
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if (!Handle || (Handle->State == csOpen) || (Handle->State == csWaitingtoOpen)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find in List
|
|
||||||
HandlePtr = &FirstHandle;
|
|
||||||
while (*HandlePtr && (*HandlePtr != Handle)) {
|
|
||||||
HandlePtr = &((*HandlePtr)->Next);
|
|
||||||
}
|
|
||||||
// Remove from list if found
|
|
||||||
if (*HandlePtr) {
|
|
||||||
*HandlePtr = (*HandlePtr)->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log event
|
|
||||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Removed",
|
|
||||||
ProcessName, Name, Handle->Name );
|
|
||||||
|
|
||||||
// Destroy Child handle
|
|
||||||
DestroyHandle( Handle );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CSelectableCore::DestroyHandle( THandle * Handle )
|
|
||||||
{
|
|
||||||
// Validate Handle
|
|
||||||
if (!Handle)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// 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->AddressInfo)
|
|
||||||
freeaddrinfo( Handle->AddressList );
|
|
||||||
|
|
||||||
// Destroy Buffers
|
|
||||||
if (Handle->InBuffer)
|
|
||||||
delete Handle->InBuffer;
|
|
||||||
if (Handle->OutBuffer)
|
|
||||||
delete Handle->OutBuffer;
|
|
||||||
|
|
||||||
// Clear Input Markers
|
|
||||||
if (Handle->InMarker)
|
|
||||||
free( Handle->InMarker );
|
|
||||||
|
|
||||||
// Destroy Pointer
|
|
||||||
free( Handle );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CSelectableCore::SetSerialHandle( THandle * Handle, const char * FileName )
|
bool CSelectableCore::SetSerialHandle( THandle * Handle, const char * FileName )
|
||||||
{
|
{
|
||||||
// Validate
|
// Validate
|
||||||
@@ -511,121 +390,6 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
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::SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback )
|
|
||||||
{
|
|
||||||
// Validate
|
|
||||||
if (!Handle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set callback
|
|
||||||
Handle->StateCallback[ (int)pState ] = pCallback;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CSelectableCore::SetAutoManage( THandle * Handle, bool AutoManage, bool Persistent, int ReopenDelay, int CloseTimeout )
|
|
||||||
{
|
|
||||||
// Validate
|
|
||||||
if (!Handle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set params
|
|
||||||
Handle->AutoManage = AutoManage;
|
|
||||||
Handle->Persistent = Persistent;
|
|
||||||
Handle->ReopenDelay = ReopenDelay;
|
|
||||||
Handle->CloseTimeout = CloseTimeout;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CSelectableCore::SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen )
|
|
||||||
{
|
|
||||||
// Validate
|
|
||||||
if (!Handle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Input Buffer
|
|
||||||
if (Handle->InBuffer) {
|
|
||||||
delete Handle->InBuffer;
|
|
||||||
Handle->InBuffer = NULL;
|
|
||||||
}
|
|
||||||
if (InBufSize) {
|
|
||||||
Handle->InBuffer = (CRollingBuffer*) new CRollingBuffer( InBufSize );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Input Timeout
|
|
||||||
Handle->InTimeout = InTimeout;
|
|
||||||
|
|
||||||
// Set Input Markers
|
|
||||||
if (InMarkerLen && InMarker) {
|
|
||||||
Handle->InMarkerLen = InMarkerLen;
|
|
||||||
Handle->InMarker = strndup( InMarker, InMarkerLen );
|
|
||||||
Handle->InMarker[InMarkerLen] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool CSelectableCore::SetOutBuffer( THandle * Handle, int OutBufSize )
|
|
||||||
{
|
|
||||||
// Validate
|
|
||||||
if (!Handle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output Buffer
|
|
||||||
if (Handle->OutBuffer) {
|
|
||||||
delete Handle->OutBuffer;
|
|
||||||
Handle->OutBuffer = NULL;
|
|
||||||
}
|
|
||||||
if (OutBufSize) {
|
|
||||||
Handle->OutBuffer = (CRollingBuffer*) new CRollingBuffer( OutBufSize );
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
THandle * CSelectableCore::OpenSerialPort( THandle * Handle )
|
THandle * CSelectableCore::OpenSerialPort( THandle * Handle )
|
||||||
{
|
{
|
||||||
// Validate
|
// Validate
|
||||||
@@ -2177,130 +1941,6 @@ bool CSelectableCore::Write( THandle * Handle )
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool CSelectableCore::ProcessInputBuffer( THandle * Handle, bool Force )
|
|
||||||
{
|
|
||||||
int Pos = 0;
|
|
||||||
int Len = 0;
|
|
||||||
char * Data = NULL;
|
|
||||||
|
|
||||||
// Check if buffered data
|
|
||||||
if (!Handle || !Handle->InBuffer || !Handle->InBuffer->Len()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if forced processed
|
|
||||||
if (Force || (!Handle->InMarkerLen && !Handle->InTimeout))
|
|
||||||
{
|
|
||||||
// Show Packet
|
|
||||||
Len = Handle->InBuffer->Peek( &Data );
|
|
||||||
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - IN-T:",
|
|
||||||
ProcessName, Name, Handle->Name );
|
|
||||||
|
|
||||||
// Write buffer to Outputs
|
|
||||||
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
|
|
||||||
Output( Handle->Parent->Channel, Data, Len );
|
|
||||||
} else {
|
|
||||||
Output( Handle->Channel, Data, Len );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear processed bytes from buffer
|
|
||||||
Handle->InBuffer->Clear( Len );
|
|
||||||
}
|
|
||||||
else if (Handle->InMarkerLen)
|
|
||||||
{
|
|
||||||
// Search for end of packet marker
|
|
||||||
while (Handle->InBuffer->FindStr( Handle->InMarker, Handle->InMarkerLen, Pos ))
|
|
||||||
{
|
|
||||||
// Show Packet
|
|
||||||
Len = Handle->InBuffer->Peek( &Data, 0, Pos+Handle->InMarkerLen );
|
|
||||||
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Handle '%s' - IN-M:",
|
|
||||||
ProcessName, Name, Handle->Name );
|
|
||||||
|
|
||||||
// Write buffer to Outputs
|
|
||||||
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
|
|
||||||
Output( Handle->Parent->Channel, Data, Len );
|
|
||||||
} else {
|
|
||||||
Output( Handle->Channel, Data, Len );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear processed bytes from buffer
|
|
||||||
Handle->InBuffer->Clear( Len );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int CSelectableCore::ReadFromFD( int FD, char * Data, int MaxLen )
|
|
||||||
{
|
|
||||||
int BytesRead = 0;
|
|
||||||
int TotalRead = 0;
|
|
||||||
int DataRemain = MaxLen;
|
|
||||||
bool Error = false;
|
|
||||||
|
|
||||||
// Check if buffer created
|
|
||||||
if ((FD == -1) || (MaxLen < 1)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read Data into buffer
|
|
||||||
while (DataRemain)
|
|
||||||
{
|
|
||||||
// Read from file descriptor
|
|
||||||
BytesRead = read( FD, &Data[TotalRead], DataRemain );
|
|
||||||
if ((BytesRead < 0)) {
|
|
||||||
Error = true;
|
|
||||||
errno = (!BytesRead)? 0 : errno; // No error if no bytes written
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Data Pointers
|
|
||||||
TotalRead += BytesRead;
|
|
||||||
DataRemain -= BytesRead;
|
|
||||||
|
|
||||||
if (DataRemain) {
|
|
||||||
usleep( 500 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (Error)? -TotalRead : TotalRead; // Report negative total on error
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int CSelectableCore::WriteToFD( int FD, const char * Data, int Len, bool Force )
|
|
||||||
{
|
|
||||||
int BytesWritten = 0;
|
|
||||||
int TotalWritten = 0;
|
|
||||||
int DataRemain = (Len != -1)? Len : (Data)? strlen(Data) : 0;
|
|
||||||
bool Error = false;
|
|
||||||
|
|
||||||
// Check if buffer created
|
|
||||||
if ((FD == -1) || !DataRemain) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read Data into buffer
|
|
||||||
while (DataRemain)
|
|
||||||
{
|
|
||||||
// Read from file descriptor
|
|
||||||
BytesWritten = write( FD, &Data[TotalWritten], DataRemain );
|
|
||||||
if ((BytesWritten <= 0) && (!Force || (errno != EAGAIN))) {
|
|
||||||
Error = true;
|
|
||||||
errno = (!BytesWritten)? 0 : errno; // No error if no bytes written
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Data Pointers
|
|
||||||
TotalWritten += BytesWritten;
|
|
||||||
DataRemain -= BytesWritten;
|
|
||||||
|
|
||||||
if (DataRemain) {
|
|
||||||
usleep( 500 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (Error)? -TotalWritten : TotalWritten; // Report negative total on error
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int CSelectableCore::ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen )
|
int CSelectableCore::ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen )
|
||||||
{
|
{
|
||||||
int BytesRead = 0;
|
int BytesRead = 0;
|
||||||
@@ -2348,62 +1988,6 @@ int CSelectableCore::WriteToUDP( THandle * Handle, const char * Data, int Len, b
|
|||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
int CSelectableCore::Input( const char * ChannelName, const char * Data, int Len )
|
|
||||||
{
|
|
||||||
TChannel * Channel = NULL;
|
|
||||||
THandle * Handle = NULL;
|
|
||||||
int HandleCount = 0;
|
|
||||||
int TempWritten = 0;
|
|
||||||
int BytesWritten = 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' - Input rejected, Channel not found",
|
|
||||||
ProcessName, Name, ChannelName );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (!Channel->InputEnabled) {
|
|
||||||
// Channel disabled
|
|
||||||
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled",
|
|
||||||
ProcessName, Name, ChannelName );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log event
|
|
||||||
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
|
|
||||||
ProcessName, Name, ChannelName );
|
|
||||||
|
|
||||||
// Find Linked handle
|
|
||||||
Handle = FirstHandle;
|
|
||||||
while( Handle )
|
|
||||||
{
|
|
||||||
if (Handle->Channel && !strcasecmp( ChannelName, Handle->Channel->Name ))
|
|
||||||
{
|
|
||||||
// Input to Handle
|
|
||||||
TempWritten = OutputHandle( Handle, Data, Len );
|
|
||||||
BytesWritten = (TempWritten > BytesWritten)? TempWritten : BytesWritten;
|
|
||||||
HandleCount++;
|
|
||||||
}
|
|
||||||
Handle = Handle->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HandleCount) {
|
|
||||||
// Handle not found
|
|
||||||
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles not found",
|
|
||||||
ProcessName, Name, ChannelName );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BytesWritten;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len )
|
int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len )
|
||||||
{
|
{
|
||||||
THandle * ChildHandle = NULL;
|
THandle * ChildHandle = NULL;
|
||||||
@@ -2887,79 +2471,3 @@ 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] = strndup( StartPos, Len );
|
|
||||||
Args[Count][Len] = 0;
|
|
||||||
Count++;
|
|
||||||
ParamStarted = false;
|
|
||||||
OpenQuotes = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Whitespace ends parameter
|
|
||||||
if ((*MatchPos == ' ') || (*MatchPos == 0)) {
|
|
||||||
Len = MatchPos-StartPos;
|
|
||||||
Args[Count] = strndup( 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;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|||||||
107
SelectableCore.h
107
SelectableCore.h
@@ -46,10 +46,11 @@ typedef struct SSelectHandle TSelectHandle;
|
|||||||
typedef struct SHandle THandle;
|
typedef struct SHandle THandle;
|
||||||
|
|
||||||
class CSelect;
|
class CSelect;
|
||||||
|
class CSelectableBare;
|
||||||
class CSelectableCore;
|
class CSelectableCore;
|
||||||
|
|
||||||
// Callback function for handle events
|
// Callback function for handle events
|
||||||
typedef void (*FHandleCallback)( CSelectableCore * Function, THandle * Handle, EConnectState State );
|
typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState State );
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ struct SSelectHandle {
|
|||||||
|
|
||||||
// Event Object
|
// Event Object
|
||||||
THandle * Handle = NULL;
|
THandle * Handle = NULL;
|
||||||
CSelectableCore * Function = NULL;
|
CSelectableBare * Function = NULL;
|
||||||
|
|
||||||
// List
|
// List
|
||||||
TSelectHandle * Next = NULL;
|
TSelectHandle * Next = NULL;
|
||||||
@@ -165,7 +166,7 @@ public:
|
|||||||
|
|
||||||
// Manage FDs
|
// Manage FDs
|
||||||
void Clear();
|
void Clear();
|
||||||
void Add( int FD, bool Read, bool Write, THandle * Handle, CSelectableCore * Function = NULL);
|
void Add( int FD, bool Read, bool Write, THandle * Handle, CSelectableBare * Function = NULL);
|
||||||
void Remove( int FD, bool Read, bool Write );
|
void Remove( int FD, bool Read, bool Write );
|
||||||
|
|
||||||
// Testing FDs
|
// Testing FDs
|
||||||
@@ -181,7 +182,7 @@ CFunctionCore * NewSelectableCore( const char * Name );
|
|||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
class CSelectableCore : public CFunctionCore
|
class CSelectableBare : public CFunctionCore
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
// FDs
|
// FDs
|
||||||
@@ -209,35 +210,10 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port Operations
|
|
||||||
THandle * OpenSerialPort( THandle * Handle );
|
|
||||||
bool WriteSerialConfig( THandle * Handle );
|
|
||||||
bool ReadSerialConfig( THandle * Handle );
|
|
||||||
|
|
||||||
THandle * OpenLinePrinterPort( THandle * Handle );
|
|
||||||
|
|
||||||
// File Socket Operations
|
|
||||||
THandle * OpenForkPipe( THandle * Handle );
|
|
||||||
THandle * OpenUNIXserverSocket( THandle * Handle );
|
|
||||||
THandle * OpenUNIXclientSocket( THandle * Handle );
|
|
||||||
THandle * OpenUNIXremoteSocket( THandle * Handle );
|
|
||||||
|
|
||||||
// Socket Operations
|
|
||||||
bool ResolveAddress( THandle * Handle, bool DelayResolve );
|
|
||||||
THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve );
|
|
||||||
THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort );
|
|
||||||
THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve );
|
|
||||||
THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve );
|
|
||||||
THandle * OpenTCPremoteSocket( THandle * Handle );
|
|
||||||
THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve );
|
|
||||||
|
|
||||||
// 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 );
|
||||||
|
|
||||||
int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen );
|
|
||||||
int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force );
|
|
||||||
|
|
||||||
// Buffer operations
|
// Buffer operations
|
||||||
virtual bool ProcessInputBuffer( THandle * Handle, bool Force );
|
virtual bool ProcessInputBuffer( THandle * Handle, bool Force );
|
||||||
|
|
||||||
@@ -253,11 +229,11 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Life Cycle
|
// Life Cycle
|
||||||
CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE );
|
CSelectableBare( const char * Name, const char * Type = TYPE_SELECTABLE );
|
||||||
virtual ~CSelectableCore();
|
virtual ~CSelectableBare();
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
virtual bool Init( CDataMember * FunctionConfig );
|
virtual bool Init( CDataMember * FunctionConfig ) = 0;
|
||||||
|
|
||||||
// Finding Handles
|
// Finding Handles
|
||||||
inline THandle * GetHandle( const char * HandleName )
|
inline THandle * GetHandle( const char * HandleName )
|
||||||
@@ -287,17 +263,10 @@ public:
|
|||||||
bool SetOutBuffer( THandle * Handle, int OutBufSize );
|
bool SetOutBuffer( THandle * Handle, int OutBufSize );
|
||||||
|
|
||||||
// Specific port parameters
|
// Specific port parameters
|
||||||
bool SetSerialHandle( THandle * Handle, const char * FileName );
|
|
||||||
bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait );
|
|
||||||
bool SetLinePrinterHandle( THandle * Handle, const char * FileName );
|
|
||||||
bool SetForkPipeHandle( THandle * Handle, const char * ExecPath );
|
|
||||||
bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue );
|
|
||||||
bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay );
|
|
||||||
|
|
||||||
bool ClearHandle( THandle * Handle );
|
bool ClearHandle( THandle * Handle );
|
||||||
|
|
||||||
// FD Operations
|
// FD Operations
|
||||||
virtual int Open( THandle * Handle, bool DelayResolve = false );
|
virtual int Open( THandle * Handle, bool DelayResolve = false ) = 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 );
|
||||||
@@ -332,4 +301,62 @@ public:
|
|||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CSelectableCore : public CSelectableBare
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// Port Operations
|
||||||
|
THandle * OpenSerialPort( THandle * Handle );
|
||||||
|
bool WriteSerialConfig( THandle * Handle );
|
||||||
|
bool ReadSerialConfig( THandle * Handle );
|
||||||
|
|
||||||
|
THandle * OpenLinePrinterPort( THandle * Handle );
|
||||||
|
|
||||||
|
// File Socket Operations
|
||||||
|
THandle * OpenForkPipe( THandle * Handle );
|
||||||
|
THandle * OpenUNIXserverSocket( THandle * Handle );
|
||||||
|
THandle * OpenUNIXclientSocket( THandle * Handle );
|
||||||
|
THandle * OpenUNIXremoteSocket( THandle * Handle );
|
||||||
|
|
||||||
|
// Socket Operations
|
||||||
|
bool ResolveAddress( THandle * Handle, bool DelayResolve );
|
||||||
|
THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve );
|
||||||
|
THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort );
|
||||||
|
THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve );
|
||||||
|
THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve );
|
||||||
|
THandle * OpenTCPremoteSocket( THandle * Handle );
|
||||||
|
THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve );
|
||||||
|
|
||||||
|
// Mutual Operations
|
||||||
|
int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen );
|
||||||
|
int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force );
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Life Cycle
|
||||||
|
CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE );
|
||||||
|
virtual ~CSelectableCore();
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
virtual bool Init( CDataMember * FunctionConfig );
|
||||||
|
|
||||||
|
// Specific port parameters
|
||||||
|
bool SetSerialHandle( THandle * Handle, const char * FileName );
|
||||||
|
bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait );
|
||||||
|
bool SetLinePrinterHandle( THandle * Handle, const char * FileName );
|
||||||
|
bool SetForkPipeHandle( THandle * Handle, const char * ExecPath );
|
||||||
|
bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue );
|
||||||
|
bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay );
|
||||||
|
|
||||||
|
// FD Operations
|
||||||
|
virtual int Open( THandle * Handle, bool DelayResolve = false );
|
||||||
|
virtual bool Close( THandle * Handle, bool QuickReopen );
|
||||||
|
virtual bool Read( THandle * Handle );
|
||||||
|
virtual bool Write( THandle * Handle );
|
||||||
|
|
||||||
|
// Function Interface
|
||||||
|
int OutputHandle( THandle * Handle, const char * Data, int Len );
|
||||||
|
virtual bool Process();
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#endif /* REDACORE_SELECTABLECORE_H_ */
|
#endif /* REDACORE_SELECTABLECORE_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user