Important Update:

- Converted Select functions into new class CSelectCore
- Move Read/Write code from main() to SelectableCore Read()/Write()
- Pass CSelectCore object to CSelectableCore on create
- Updated SelectCore Read/Write lists directly from SelectableCore
- SelectCore->Test() checks all FDs directly and call Read/Write functions
- Improved checking/validating for methods in SelectableCore
This commit is contained in:
Charl Wentzel
2016-05-24 15:02:51 +02:00
parent dcfbd85efa
commit e83c09ecb6
4 changed files with 361 additions and 113 deletions

View File

@@ -55,8 +55,8 @@ public:
bool FindChar( char SearchChar, int &FoundPos, int StartPos = 0 );
// Miscellaneous
int Size() { return BufSize; };
int Len() { return BufLen; };
inline int Size() { return BufSize; };
inline int Len() { return BufLen; };
};
//---------------------------------------------------------------------------

View File

@@ -8,24 +8,40 @@
// redA Libraries
#include "TimingCore.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "SelectableCore.h"
//---------------------------------------------------------------------------
// Select Variables
fd_set ReadTestFDS;
fd_set WriteTestFDS;
fd_set ReadFDS;
fd_set WriteFDS;
int MaxFD = 0;
timeval SelectTime;
// Create Select
CSelect::CSelect( long SelectTimeout )
{
// Clear List
FirstHandle = NULL;
// Clear Select sets
FD_ZERO( &ReadTestFDS );
FD_ZERO( &WriteTestFDS );
// Reset maximum File Descriptor
MaxFD = 0;
// Set Timeout
SetInterval( &Timeout, SelectTimeout );
}
//---------------------------------------------------------------------------
// Destroy Select
CSelect::~CSelect()
{
return;
}
//---------------------------------------------------------------------------
// Clear Select File Descriptors
void SelectClear()
void CSelect::Clear()
{
// Clear Select sets
FD_ZERO( &ReadTestFDS );
@@ -36,24 +52,39 @@ void SelectClear()
}
//---------------------------------------------------------------------------
// Set Select timeout
void SelectConfig( long SelectTimeout )
{
// Set Timeout
SetInterval( &SelectTime, SelectTimeout );
}
//---------------------------------------------------------------------------
// Add Select File Descriptor
void SelectAdd( int FD, bool Read, bool Write )
void CSelect::Add( int FD, bool Read, bool Write, CSelectableCore * Function )
{
TSelectHandle ** Handle = NULL;
// Check if Handle already exists
Handle = &FirstHandle;
while (*Handle && ((*Handle)->FD != FD)) {
Handle = &((*Handle)->Next);
}
// Create if not exist
if (!*Handle) {
// Create
*Handle = (TSelectHandle*)malloc( sizeof(TSelectHandle) );
memset( *Handle, 0, sizeof(TSelectHandle) );
// Set Parameters
(*Handle)->FD = FD;
(*Handle)->Function = Function;
}
// Add Read select
if (Read)
if (Read) {
(*Handle)->Read = true;
FD_SET( FD, &ReadTestFDS );
}
// Add Write Select
if (Write)
if (Write) {
(*Handle)->Write = true;
FD_SET( FD, &WriteTestFDS );
}
// Check Maximum File Handle
if (MaxFD <= FD)
@@ -61,19 +92,42 @@ void SelectAdd( int FD, bool Read, bool Write )
}
//---------------------------------------------------------------------------
void SelectRemove( int FD, bool Read, bool Write )
void CSelect::Remove( int FD, bool Read, bool Write )
{
TSelectHandle ** Handle = NULL;
TSelectHandle * NextHandle = NULL;
int TestFD = 0;
// Check if Handle already exists
Handle = &FirstHandle;
while (*Handle && ((*Handle)->FD != FD)) {
Handle = &((*Handle)->Next);
}
// Check if found
if (!*Handle)
return;
// Remove from set for select read check
if (Read)
if (Read) {
(*Handle)->Read = false;
FD_CLR( FD, &ReadTestFDS);
}
// Remove from set for select write check
if (Write)
if (Write) {
(*Handle)->Write = false;
FD_CLR( FD, &WriteTestFDS);
}
// Check Maximum file handle
// Check if to remove from list
if (!(*Handle)->Read && !(*Handle)->Write)
{
// Remove from list
NextHandle = (*Handle)->Next;
free( *Handle );
*Handle = NextHandle;
// Update Maximum Test FD
if (FD == MaxFD-1) {
for (TestFD = MaxFD-1; TestFD >= 0; TestFD--) {
if (FD_ISSET( TestFD, &ReadTestFDS ) || FD_ISSET( TestFD, &WriteTestFDS )) {
@@ -82,39 +136,46 @@ void SelectRemove( int FD, bool Read, bool Write )
}
MaxFD = TestFD+1;
}
}
}
//---------------------------------------------------------------------------
bool SelectTest()
bool CSelect::Test()
{
int Result = 0;
TSelectHandle * Handle = NULL;
int Events = 0;
// Set Test sets
ReadFDS = ReadTestFDS;
WriteFDS = WriteTestFDS;
// Perform select
Result = select( MaxFD, &ReadFDS, &WriteFDS, (fd_set*)NULL, &SelectTime );
if (Result < 0)
Events = select( MaxFD, &ReadFDS, &WriteFDS, (fd_set*)NULL, &Timeout );
if (Events < 0)
{
printf( "Select operation failed (%s)\n", strerror(errno) );
return false;
}
// Check all descriptors for events
Handle = FirstHandle;
while (Handle)
{
// Check read Event
if (FD_ISSET( Handle->FD, &ReadFDS ) && Handle->Function) {
Handle->Function->Read( Handle->FD );
}
// Check Write Event
if (FD_ISSET( Handle->FD, &WriteFDS ) && Handle->Function) {
Handle->Function->Write( Handle->FD );
}
// Next
Handle = Handle->Next;
}
// return success
return (bool)Result;
}
//---------------------------------------------------------------------------
// Add Select File Descriptor
bool SelectCheck( int FD, bool &Read, bool &Write )
{
// Add Read select
Read = (bool)(FD_ISSET( FD, &ReadFDS ));
// Add Write Select
Write = (bool)(FD_ISSET( FD, &WriteFDS ));
return (Read || Write);
return (bool)Events;
}
//---------------------------------------------------------------------------

View File

@@ -31,11 +31,14 @@
//---------------------------------------------------------------------------
CSelectableCore::CSelectableCore( const char * Name ) :
CSelectableCore::CSelectableCore( const char * Name, CSelect * Selector ) :
CFunctionCore( Name )
{
// Handles
FirstHandle = NULL;
// Select
Select = Selector;
}
//---------------------------------------------------------------------------
@@ -86,7 +89,7 @@ bool CSelectableCore::RemoveHandle( THandle * Handle )
THandle ** HandlePtr = NULL;
// Validate
if (!Handle || (Handle->Type != ctRemoteClient)) {
if (!Handle || (Handle->State == csOpen) || (Handle->State == csWaitingtoOpen)) {
return false;
}
@@ -146,7 +149,7 @@ bool CSelectableCore::SetPortHandle( const char * HandleName, const char * FileN
}
// Search for file handle
if (!(Handle = GetHandle( HandleName ))) {
if (!(Handle = GetHandle( HandleName )) || (Handle->Type != ctNone)) {
return false;
}
@@ -171,20 +174,15 @@ bool CSelectableCore::SetSocketHandle( const char * HandleName, EConnectType Ty
THandle * Handle = NULL;
// Validate
if (!Address || (Type == ctNone)) {
if (!Address || (Type == ctNone) || (Type == ctPort)) {
return false;
}
// Search for file handle
if (!(Handle = GetHandle( HandleName ))) {
if (!(Handle = GetHandle( HandleName )) || (Handle->Type != ctNone)) {
return false;
}
// Clear File Name
if (Handle->FileName) {
free( Handle->FileName );
}
// Set Type
Handle->Type = Type;
Handle->KeepAlive = KeepAlive;
@@ -292,6 +290,7 @@ int CSelectableCore::OpenPort( THandle * Handle )
}
// Confirm open
Handle->State = csOpen;
printf( "Port: %s -> Port opened\n", Handle->Name );
return Handle->FD;
}
@@ -354,6 +353,10 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
return -1;
}
// Set non-blocking flag
int flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, flags | O_NONBLOCK );
// Bind socket
if (bind( Handle->FD, (struct sockaddr *)&address, addr_len ) < 0)
{
@@ -383,14 +386,15 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
{
THandle ** RemoteClient;
int ClientFD;
char ClientAddress[25];
char ClientAddress[100];
char ClientName[100];
socklen_t addr_len;
struct sockaddr_in address;
// Validate
if (!Handle) {
return false;
return -1;
}
// Check Handle type
@@ -400,14 +404,17 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
addr_len = sizeof( address );
if ((ClientFD = accept( Handle->FD, (struct sockaddr *)&address, &addr_len)) == -1)
{
if (errno == EWOULDBLOCK)
printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", (*RemoteClient)->Address, strerror(errno) );
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", Handle->Address, strerror(errno) );
else
printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", (*RemoteClient)->Address, strerror(errno) );
close( ClientFD );
printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", Handle->Address, strerror(errno) );
return -1;
}
// Set non-blocking flag
int flags = fcntl( ClientFD, F_GETFL, 0 );
fcntl( ClientFD, F_SETFL, flags | O_NONBLOCK );
// Return client address
strcpy( ClientAddress, inet_ntoa(address.sin_addr) );
@@ -418,32 +425,31 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
}
// Create Remote Client Handle
*RemoteClient = CreateHandle( "Client" );
SetSocketHandle( "Client", ctRemoteClient, ClientAddress, 0, Handle->KeepAlive );
SetBuffers( "Client", 20, 0, 50, "\n", 1 );
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
*RemoteClient = CreateHandle( ClientName );
SetSocketHandle( ClientName, ctRemoteClient, ClientAddress, 0, Handle->KeepAlive );
SetBuffers( ClientName, 20, 0, 50, "\n", 1 );
(*RemoteClient)->FD = ClientFD;
(*RemoteClient)->Parent = Handle;
(*RemoteClient)->State = csOpen;
(*RemoteClient)->State = csWaitingtoOpen;
printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Handle->Address, ClientAddress );
return (*RemoteClient)->FD;
}
else if (Handle->Type == ctRemoteClient)
{
if (Handle->State == csWaitingtoOpen)
{
// Clear non blocking flag
int flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, (!O_NONBLOCK)&flags );
// Set new state
Handle->State = csOpen;
// Log event
printf( "Socket: %s -> Client now connected to server (%s)\n", Handle->Address, Handle->Parent->Address );
}
// Check state
if (Handle->State == csOpen) {
// Already open
return Handle->FD;
}
else if (Handle->State == csWaitingtoOpen) {
// Update state
Handle->State = csOpen;
return Handle->FD;
}
}
return -1;
}
//---------------------------------------------------------------------------
@@ -459,6 +465,17 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
int TCPcnt_opt = 3;
int TCPint_opt = 2;
// Check state
if (Handle->State == csOpen) {
// Already open
return Handle->FD;
}
else if (Handle->State == csWaitingtoOpen) {
// Update state
Handle->State = csOpen;
return Handle->FD;
}
// Create File descriptor
if ((Handle->FD = socket( AF_INET, SOCK_STREAM, 0 )) < 0)
{
@@ -493,8 +510,10 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
Handle->State = csOpen;
return Handle->FD;
}
else if (errno == EINPROGRESS)
else if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
printf( "Client Socket: %s -> Client waiting to connect (%s)\n", Handle->Address, strerror(errno) );
// Set status
Handle->State = csWaitingtoOpen;
return Handle->FD;
@@ -515,6 +534,7 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
int CSelectableCore::Open( const char * HandleName )
{
int FD = -1;
THandle * Handle = NULL;
// Validate
@@ -525,16 +545,26 @@ int CSelectableCore::Open( const char * HandleName )
// Open correctly
switch (Handle->Type) {
case ctPort :
return OpenPort( Handle );
FD = OpenPort( Handle );
break;
case ctServer :
return OpenServerSocket( Handle );
FD = OpenServerSocket( Handle );
break;
case ctClient :
return OpenClientSocket( Handle );
FD = OpenClientSocket( Handle );
break;
case ctRemoteClient :
return OpenRemoteClientSocket( Handle );
FD = OpenRemoteClientSocket( Handle );
break;
default:
return -1;
FD = -1;
}
// Add to Select Lists
if (Select && FD != -1) {
Select->Add( FD, true, true, this );
}
return FD;
};
//---------------------------------------------------------------------------
@@ -551,9 +581,10 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
while (ChildHandle) {
if (ChildHandle->Parent == Handle) {
NextHandle = ChildHandle->Next;
// Close and Destroy handle
// Close
Close( ChildHandle );
RemoveHandle( ChildHandle );
// Next Handle
ChildHandle = NextHandle;
} else {
@@ -563,6 +594,11 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
}
}
// Remove from Select List
if (Select) {
Select->Remove( Handle->FD, true, true );
}
// Close Handle
Fail = (close( Handle->FD ))? true : false;
Handle->State = ((Fail)? csFailed : csClosed);
@@ -600,28 +636,48 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
// Device Interface
bool CSelectableCore::Read( THandle * Handle )
{
int ClientFD = -1;
int BytesRead = 0;
int BytesWaiting = 0;
int BytesWaiting = -1;
// Validate
if (!Handle) {
return false;
}
// Check for closing event on Socket
if ((Handle->Type == ctRemoteClient) || (Handle->Type == ctClient))
// Check for closing/opening event on Socket
if (Handle->Type == ctServer)
{
// Incoming client request
ClientFD = OpenRemoteClientSocket( Handle );
if (ClientFD != -1) {
// Add to Select Lists
if (Select) {
Select->Add( ClientFD, true, true, this );
}
return true;
}
}
else if ((Handle->Type == ctRemoteClient) || (Handle->Type == ctClient))
{
// Check if anything to read
ioctl( Handle->FD, FIONREAD, &BytesWaiting );
if (!BytesWaiting) {
// EOF from server (close connection)
// EOF from server
if (!BytesWaiting)
{
// Close Handle
Close( Handle );
// Destroy Remote Client
if (Handle->Type == ctRemoteClient) {
RemoveHandle( Handle );
}
return false;
}
// Check if socket ready (non-block open not in progress)
else if (Handle->State == csWaitingtoOpen) {
// Check if socket ready (non-block open in progress)
else if (Handle->State == csWaitingtoOpen)
{
printf( "Socket: %s -> Cannot read from socket in waiting\n", Name );
return false;
}
@@ -633,8 +689,9 @@ bool CSelectableCore::Read( THandle * Handle )
}
// Read File directly into buffer
if (!(BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD )))
if (!(BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD ))) {
return false;
}
// Process Buffer
ProcessBuffer( Handle, false );
@@ -648,12 +705,59 @@ bool CSelectableCore::Read( THandle * Handle )
bool CSelectableCore::Write( THandle * Handle )
{
int BytesWritten = 0;
// Validate
if (!Handle || (Handle->State != csOpen)) {
if (!Handle) {
return false;
}
if (Handle->State == csWaitingtoOpen)
{
// Complete socket open
if (Handle->Type == ctRemoteClient) {
OpenRemoteClientSocket( Handle );
} else if (Handle->Type == ctClient) {
OpenClientSocket( Handle );
}
// Remove from set for select write
if (Select) {
Select->Remove( Handle->FD, false, true );
}
return true;
}
else if (Handle->State == csOpen)
{
if (Handle->OutBuffer)
{
// Write to FD directly from buffer
if (!(BytesWritten = Handle->OutBuffer->WriteToFD( Handle->FD ))) {
return false;
}
// Update Buffer
Handle->OutBuffer->Clear( BytesWritten );
// Check if Buffer emtpy
if (Handle->OutBuffer->Len()) {
// Add to Select Write list
if (Select) {
Select->Remove( Handle->FD, false, true );
}
}
}
else
{
// No Output buffer, so remove from Write list
if (Select) {
Select->Remove( Handle->FD, false, true );
}
}
return true;
}
return false;
}
//---------------------------------------------------------------------------
@@ -685,6 +789,35 @@ bool CSelectableCore::Process()
}
//---------------------------------------------------------------------------
int CSelectableCore::ReadFromFD( int FD, char * Data, int MaxLen )
{
int BytesRead = 0;
int TotalRead = 0;
int DataRemain = 0;
// Check if buffer created
if ((FD == -1) || !Data) {
return 0;
}
// Read Data into buffer
DataRemain = (MaxLen == -1)? strlen(Data) : MaxLen;
while (DataRemain)
{
// Read from file descriptor
BytesRead = read( FD, Data, DataRemain );
if (BytesRead <= 0)
break;
// Update Data Pointers
TotalRead += BytesRead;
DataRemain -= BytesRead;
}
return TotalRead;
}
//---------------------------------------------------------------------------
int CSelectableCore::WriteToFD( int FD, const char * Data, int Len )
{
int BytesWritten = 0;
@@ -720,7 +853,7 @@ int CSelectableCore::Input( int FD, const char * Data, int Len )
int BytesWritten = 0;
// Get File handle
if ((Handle = GetHandle( FD ))) {
if ((Handle = GetHandle( "Serial Port" )) || (Handle = GetHandle( "Client" ))) {
// Write to handle
BytesWritten = WriteToFD( Handle->FD, Data, Len );
}

View File

@@ -38,16 +38,32 @@ const char ConnectStateName[][15] = { "None", "WaitingToOpen", "Open", "DataWait
//---------------------------------------------------------------------------
void SelectConfig( long Timeout );
void SelectClear();
void SelectAdd( int FD, bool Read, bool Write );
void SelectRemove( int FD, bool Read, bool Write );
bool SelectTest();
bool SelectCheck( int FD, bool &Read, bool &Write );
// Previews
typedef struct SSelectHandle TSelectHandle;
typedef struct SHandle THandle;
class CSelect;
class CSelectableCore;
//---------------------------------------------------------------------------
typedef struct SHandle THandle;
// List of Handles for Select Object
struct SSelectHandle {
// File Descriptor
int FD;
bool Read;
bool Write;
// Event Object
CSelectableCore * Function;
// List
TSelectHandle * Next;
};
//---------------------------------------------------------------------------
// List or Handles for Selectable Function Object
struct SHandle {
// Description
char * Name;
@@ -74,18 +90,56 @@ struct SHandle {
timeval InStart;
long InTimeout; // millisecs
// List / Tree
THandle * Parent;
THandle * Next;
};
//---------------------------------------------------------------------------
class CSelect
{
protected:
// List
TSelectHandle * FirstHandle;
// Select Variables
fd_set ReadTestFDS;
fd_set WriteTestFDS;
fd_set ReadFDS;
fd_set WriteFDS;
// Configuration
int MaxFD;
timeval Timeout;
public:
// Life Cycle
CSelect( long SelectTimeout );
~CSelect();
// Manage FDs
void Clear();
void Add( int FD, bool Read, bool Write, CSelectableCore * Function = NULL);
void Remove( int FD, bool Read, bool Write );
// Testing FDs
bool Test();
bool Check( int FD, bool &Read, bool &Write );
};
//---------------------------------------------------------------------------
class CSelectableCore : public CFunctionCore
{
protected:
// Device Interfaces
// FDs
THandle * FirstHandle;
// Select interface
CSelect * Select;
// Managing File Handles
bool RemoveHandle( THandle * Handle );
bool DestroyHandle( THandle * Handle );
@@ -113,7 +167,7 @@ protected:
// Socket Operations
virtual int OpenServerSocket( THandle * Handle );
//virtual int OpenRemoteClientSocket( THandle * Handle );
virtual int OpenRemoteClientSocket( THandle * Handle );
virtual int OpenClientSocket( THandle * Handle );
// Mutual Operations
@@ -121,6 +175,7 @@ protected:
virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle );
int ReadFromFD( int FD, char * Data, int MaxLen );
int WriteToFD( int FD, const char * Data, int Len );
// Buffer operations
@@ -128,7 +183,7 @@ protected:
public:
// Life Cycle
CSelectableCore( const char * Name );
CSelectableCore( const char * Name, CSelect * Selector );
~CSelectableCore();
// Configuration
@@ -142,7 +197,6 @@ public:
bool ClearHandle( const char * HandleName );
virtual int Open( const char * HandleName );
virtual int OpenRemoteClientSocket( THandle * Handle );
virtual bool Close( const char * HandleName, bool CloseChildren = false ) { return (Close( GetHandle( HandleName ), CloseChildren )); };
virtual bool Close( int FD, bool CloseChildren = false ) { return (Close( GetHandle( FD ), CloseChildren )); };