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:
@@ -55,8 +55,8 @@ public:
|
|||||||
bool FindChar( char SearchChar, int &FoundPos, int StartPos = 0 );
|
bool FindChar( char SearchChar, int &FoundPos, int StartPos = 0 );
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
int Size() { return BufSize; };
|
inline int Size() { return BufSize; };
|
||||||
int Len() { return BufLen; };
|
inline int Len() { return BufLen; };
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
155
SelectCore.cpp
155
SelectCore.cpp
@@ -8,24 +8,40 @@
|
|||||||
// redA Libraries
|
// redA Libraries
|
||||||
#include "TimingCore.h"
|
#include "TimingCore.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "SelectableCore.h"
|
#include "SelectableCore.h"
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
// Select Variables
|
// Create Select
|
||||||
fd_set ReadTestFDS;
|
CSelect::CSelect( long SelectTimeout )
|
||||||
fd_set WriteTestFDS;
|
{
|
||||||
fd_set ReadFDS;
|
// Clear List
|
||||||
fd_set WriteFDS;
|
FirstHandle = NULL;
|
||||||
int MaxFD = 0;
|
|
||||||
timeval SelectTime;
|
|
||||||
|
|
||||||
|
// 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
|
// Clear Select File Descriptors
|
||||||
void SelectClear()
|
void CSelect::Clear()
|
||||||
{
|
{
|
||||||
// Clear Select sets
|
// Clear Select sets
|
||||||
FD_ZERO( &ReadTestFDS );
|
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
|
// 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
|
// Add Read select
|
||||||
if (Read)
|
if (Read) {
|
||||||
|
(*Handle)->Read = true;
|
||||||
FD_SET( FD, &ReadTestFDS );
|
FD_SET( FD, &ReadTestFDS );
|
||||||
|
}
|
||||||
|
|
||||||
// Add Write Select
|
// Add Write Select
|
||||||
if (Write)
|
if (Write) {
|
||||||
|
(*Handle)->Write = true;
|
||||||
FD_SET( FD, &WriteTestFDS );
|
FD_SET( FD, &WriteTestFDS );
|
||||||
|
}
|
||||||
|
|
||||||
// Check Maximum File Handle
|
// Check Maximum File Handle
|
||||||
if (MaxFD <= FD)
|
if (MaxFD <= FD)
|
||||||
@@ -61,60 +92,90 @@ 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 )
|
||||||
{
|
{
|
||||||
int TestFD = 0;
|
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
|
// Remove from set for select read check
|
||||||
if (Read)
|
if (Read) {
|
||||||
|
(*Handle)->Read = false;
|
||||||
FD_CLR( FD, &ReadTestFDS);
|
FD_CLR( FD, &ReadTestFDS);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove from set for select write check
|
// Remove from set for select write check
|
||||||
if (Write)
|
if (Write) {
|
||||||
|
(*Handle)->Write = false;
|
||||||
FD_CLR( FD, &WriteTestFDS);
|
FD_CLR( FD, &WriteTestFDS);
|
||||||
|
}
|
||||||
|
|
||||||
// Check Maximum file handle
|
// Check if to remove from list
|
||||||
if (FD == MaxFD-1) {
|
if (!(*Handle)->Read && !(*Handle)->Write)
|
||||||
for (TestFD = MaxFD-1; TestFD >= 0; TestFD--) {
|
{
|
||||||
if (FD_ISSET( TestFD, &ReadTestFDS ) || FD_ISSET( TestFD, &WriteTestFDS )) {
|
// Remove from list
|
||||||
break;
|
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 )) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
MaxFD = TestFD+1;
|
||||||
}
|
}
|
||||||
MaxFD = TestFD+1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool SelectTest()
|
bool CSelect::Test()
|
||||||
{
|
{
|
||||||
int Result = 0;
|
TSelectHandle * Handle = NULL;
|
||||||
|
int Events = 0;
|
||||||
|
|
||||||
// Set Test sets
|
// Set Test sets
|
||||||
ReadFDS = ReadTestFDS;
|
ReadFDS = ReadTestFDS;
|
||||||
WriteFDS = WriteTestFDS;
|
WriteFDS = WriteTestFDS;
|
||||||
|
|
||||||
// Perform select
|
// Perform select
|
||||||
Result = select( MaxFD, &ReadFDS, &WriteFDS, (fd_set*)NULL, &SelectTime );
|
Events = select( MaxFD, &ReadFDS, &WriteFDS, (fd_set*)NULL, &Timeout );
|
||||||
if (Result < 0)
|
if (Events < 0)
|
||||||
{
|
{
|
||||||
printf( "Select operation failed (%s)\n", strerror(errno) );
|
printf( "Select operation failed (%s)\n", strerror(errno) );
|
||||||
return false;
|
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 success
|
||||||
return (bool)Result;
|
return (bool)Events;
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -31,11 +31,14 @@
|
|||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CSelectableCore::CSelectableCore( const char * Name ) :
|
CSelectableCore::CSelectableCore( const char * Name, CSelect * Selector ) :
|
||||||
CFunctionCore( Name )
|
CFunctionCore( Name )
|
||||||
{
|
{
|
||||||
// Handles
|
// Handles
|
||||||
FirstHandle = NULL;
|
FirstHandle = NULL;
|
||||||
|
|
||||||
|
// Select
|
||||||
|
Select = Selector;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -86,7 +89,7 @@ bool CSelectableCore::RemoveHandle( THandle * Handle )
|
|||||||
THandle ** HandlePtr = NULL;
|
THandle ** HandlePtr = NULL;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (!Handle || (Handle->Type != ctRemoteClient)) {
|
if (!Handle || (Handle->State == csOpen) || (Handle->State == csWaitingtoOpen)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +149,7 @@ bool CSelectableCore::SetPortHandle( const char * HandleName, const char * FileN
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Search for file handle
|
// Search for file handle
|
||||||
if (!(Handle = GetHandle( HandleName ))) {
|
if (!(Handle = GetHandle( HandleName )) || (Handle->Type != ctNone)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,20 +174,15 @@ bool CSelectableCore::SetSocketHandle( const char * HandleName, EConnectType Ty
|
|||||||
THandle * Handle = NULL;
|
THandle * Handle = NULL;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (!Address || (Type == ctNone)) {
|
if (!Address || (Type == ctNone) || (Type == ctPort)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for file handle
|
// Search for file handle
|
||||||
if (!(Handle = GetHandle( HandleName ))) {
|
if (!(Handle = GetHandle( HandleName )) || (Handle->Type != ctNone)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear File Name
|
|
||||||
if (Handle->FileName) {
|
|
||||||
free( Handle->FileName );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Type
|
// Set Type
|
||||||
Handle->Type = Type;
|
Handle->Type = Type;
|
||||||
Handle->KeepAlive = KeepAlive;
|
Handle->KeepAlive = KeepAlive;
|
||||||
@@ -292,6 +290,7 @@ int CSelectableCore::OpenPort( THandle * Handle )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Confirm open
|
// Confirm open
|
||||||
|
Handle->State = csOpen;
|
||||||
printf( "Port: %s -> Port opened\n", Handle->Name );
|
printf( "Port: %s -> Port opened\n", Handle->Name );
|
||||||
return Handle->FD;
|
return Handle->FD;
|
||||||
}
|
}
|
||||||
@@ -354,6 +353,10 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set non-blocking flag
|
||||||
|
int flags = fcntl( Handle->FD, F_GETFL, 0 );
|
||||||
|
fcntl( Handle->FD, F_SETFL, flags | O_NONBLOCK );
|
||||||
|
|
||||||
// Bind socket
|
// Bind socket
|
||||||
if (bind( Handle->FD, (struct sockaddr *)&address, addr_len ) < 0)
|
if (bind( Handle->FD, (struct sockaddr *)&address, addr_len ) < 0)
|
||||||
{
|
{
|
||||||
@@ -383,14 +386,15 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
|
|||||||
{
|
{
|
||||||
THandle ** RemoteClient;
|
THandle ** RemoteClient;
|
||||||
int ClientFD;
|
int ClientFD;
|
||||||
char ClientAddress[25];
|
char ClientAddress[100];
|
||||||
|
char ClientName[100];
|
||||||
|
|
||||||
socklen_t addr_len;
|
socklen_t addr_len;
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (!Handle) {
|
if (!Handle) {
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Handle type
|
// Check Handle type
|
||||||
@@ -400,14 +404,17 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
|
|||||||
addr_len = sizeof( address );
|
addr_len = sizeof( address );
|
||||||
if ((ClientFD = accept( Handle->FD, (struct sockaddr *)&address, &addr_len)) == -1)
|
if ((ClientFD = accept( Handle->FD, (struct sockaddr *)&address, &addr_len)) == -1)
|
||||||
{
|
{
|
||||||
if (errno == EWOULDBLOCK)
|
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
|
||||||
printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", (*RemoteClient)->Address, strerror(errno) );
|
printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", Handle->Address, strerror(errno) );
|
||||||
else
|
else
|
||||||
printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", (*RemoteClient)->Address, strerror(errno) );
|
printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", Handle->Address, strerror(errno) );
|
||||||
close( ClientFD );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set non-blocking flag
|
||||||
|
int flags = fcntl( ClientFD, F_GETFL, 0 );
|
||||||
|
fcntl( ClientFD, F_SETFL, flags | O_NONBLOCK );
|
||||||
|
|
||||||
// Return client address
|
// Return client address
|
||||||
strcpy( ClientAddress, inet_ntoa(address.sin_addr) );
|
strcpy( ClientAddress, inet_ntoa(address.sin_addr) );
|
||||||
|
|
||||||
@@ -418,31 +425,30 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create Remote Client Handle
|
// Create Remote Client Handle
|
||||||
*RemoteClient = CreateHandle( "Client" );
|
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
|
||||||
SetSocketHandle( "Client", ctRemoteClient, ClientAddress, 0, Handle->KeepAlive );
|
*RemoteClient = CreateHandle( ClientName );
|
||||||
SetBuffers( "Client", 20, 0, 50, "\n", 1 );
|
SetSocketHandle( ClientName, ctRemoteClient, ClientAddress, 0, Handle->KeepAlive );
|
||||||
(*RemoteClient)->FD = ClientFD;
|
SetBuffers( ClientName, 20, 0, 50, "\n", 1 );
|
||||||
|
|
||||||
|
(*RemoteClient)->FD = ClientFD;
|
||||||
(*RemoteClient)->Parent = Handle;
|
(*RemoteClient)->Parent = Handle;
|
||||||
(*RemoteClient)->State = csOpen;
|
(*RemoteClient)->State = csWaitingtoOpen;
|
||||||
|
|
||||||
printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Handle->Address, ClientAddress );
|
printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Handle->Address, ClientAddress );
|
||||||
return (*RemoteClient)->FD;
|
return (*RemoteClient)->FD;
|
||||||
}
|
}
|
||||||
else if (Handle->Type == ctRemoteClient)
|
else if (Handle->Type == ctRemoteClient)
|
||||||
{
|
{
|
||||||
if (Handle->State == csWaitingtoOpen)
|
// Check state
|
||||||
{
|
if (Handle->State == csOpen) {
|
||||||
// Clear non blocking flag
|
// Already open
|
||||||
int flags = fcntl( Handle->FD, F_GETFL, 0 );
|
return Handle->FD;
|
||||||
fcntl( Handle->FD, F_SETFL, (!O_NONBLOCK)&flags );
|
}
|
||||||
|
else if (Handle->State == csWaitingtoOpen) {
|
||||||
// Set new state
|
// Update state
|
||||||
Handle->State = csOpen;
|
Handle->State = csOpen;
|
||||||
|
return Handle->FD;
|
||||||
// Log event
|
|
||||||
printf( "Socket: %s -> Client now connected to server (%s)\n", Handle->Address, Handle->Parent->Address );
|
|
||||||
}
|
}
|
||||||
return Handle->FD;
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -459,6 +465,17 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
|
|||||||
int TCPcnt_opt = 3;
|
int TCPcnt_opt = 3;
|
||||||
int TCPint_opt = 2;
|
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
|
// Create File descriptor
|
||||||
if ((Handle->FD = socket( AF_INET, SOCK_STREAM, 0 )) < 0)
|
if ((Handle->FD = socket( AF_INET, SOCK_STREAM, 0 )) < 0)
|
||||||
{
|
{
|
||||||
@@ -493,8 +510,10 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
|
|||||||
Handle->State = csOpen;
|
Handle->State = csOpen;
|
||||||
return Handle->FD;
|
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
|
// Set status
|
||||||
Handle->State = csWaitingtoOpen;
|
Handle->State = csWaitingtoOpen;
|
||||||
return Handle->FD;
|
return Handle->FD;
|
||||||
@@ -515,6 +534,7 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
|
|||||||
|
|
||||||
int CSelectableCore::Open( const char * HandleName )
|
int CSelectableCore::Open( const char * HandleName )
|
||||||
{
|
{
|
||||||
|
int FD = -1;
|
||||||
THandle * Handle = NULL;
|
THandle * Handle = NULL;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
@@ -525,16 +545,26 @@ int CSelectableCore::Open( const char * HandleName )
|
|||||||
// Open correctly
|
// Open correctly
|
||||||
switch (Handle->Type) {
|
switch (Handle->Type) {
|
||||||
case ctPort :
|
case ctPort :
|
||||||
return OpenPort( Handle );
|
FD = OpenPort( Handle );
|
||||||
|
break;
|
||||||
case ctServer :
|
case ctServer :
|
||||||
return OpenServerSocket( Handle );
|
FD = OpenServerSocket( Handle );
|
||||||
|
break;
|
||||||
case ctClient :
|
case ctClient :
|
||||||
return OpenClientSocket( Handle );
|
FD = OpenClientSocket( Handle );
|
||||||
|
break;
|
||||||
case ctRemoteClient :
|
case ctRemoteClient :
|
||||||
return OpenRemoteClientSocket( Handle );
|
FD = OpenRemoteClientSocket( Handle );
|
||||||
|
break;
|
||||||
default:
|
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) {
|
while (ChildHandle) {
|
||||||
if (ChildHandle->Parent == Handle) {
|
if (ChildHandle->Parent == Handle) {
|
||||||
NextHandle = ChildHandle->Next;
|
NextHandle = ChildHandle->Next;
|
||||||
// Close and Destroy handle
|
|
||||||
|
// Close
|
||||||
Close( ChildHandle );
|
Close( ChildHandle );
|
||||||
RemoveHandle( ChildHandle );
|
|
||||||
// Next Handle
|
// Next Handle
|
||||||
ChildHandle = NextHandle;
|
ChildHandle = NextHandle;
|
||||||
} else {
|
} 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
|
// Close Handle
|
||||||
Fail = (close( Handle->FD ))? true : false;
|
Fail = (close( Handle->FD ))? true : false;
|
||||||
Handle->State = ((Fail)? csFailed : csClosed);
|
Handle->State = ((Fail)? csFailed : csClosed);
|
||||||
@@ -600,28 +636,48 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
|
|||||||
// Device Interface
|
// Device Interface
|
||||||
bool CSelectableCore::Read( THandle * Handle )
|
bool CSelectableCore::Read( THandle * Handle )
|
||||||
{
|
{
|
||||||
|
int ClientFD = -1;
|
||||||
int BytesRead = 0;
|
int BytesRead = 0;
|
||||||
int BytesWaiting = 0;
|
int BytesWaiting = -1;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (!Handle) {
|
if (!Handle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for closing event on Socket
|
// Check for closing/opening event on Socket
|
||||||
if ((Handle->Type == ctRemoteClient) || (Handle->Type == ctClient))
|
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
|
// Check if anything to read
|
||||||
ioctl( Handle->FD, FIONREAD, &BytesWaiting );
|
ioctl( Handle->FD, FIONREAD, &BytesWaiting );
|
||||||
|
|
||||||
if (!BytesWaiting) {
|
// EOF from server
|
||||||
// EOF from server (close connection)
|
if (!BytesWaiting)
|
||||||
|
{
|
||||||
|
// Close Handle
|
||||||
Close( Handle );
|
Close( Handle );
|
||||||
RemoveHandle( Handle );
|
|
||||||
|
// Destroy Remote Client
|
||||||
|
if (Handle->Type == ctRemoteClient) {
|
||||||
|
RemoveHandle( Handle );
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check if socket ready (non-block open not in progress)
|
// Check if socket ready (non-block open in progress)
|
||||||
else if (Handle->State == csWaitingtoOpen) {
|
else if (Handle->State == csWaitingtoOpen)
|
||||||
|
{
|
||||||
printf( "Socket: %s -> Cannot read from socket in waiting\n", Name );
|
printf( "Socket: %s -> Cannot read from socket in waiting\n", Name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -633,8 +689,9 @@ bool CSelectableCore::Read( THandle * Handle )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read File directly into buffer
|
// Read File directly into buffer
|
||||||
if (!(BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD )))
|
if (!(BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD ))) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Process Buffer
|
// Process Buffer
|
||||||
ProcessBuffer( Handle, false );
|
ProcessBuffer( Handle, false );
|
||||||
@@ -648,12 +705,59 @@ bool CSelectableCore::Read( THandle * Handle )
|
|||||||
|
|
||||||
bool CSelectableCore::Write( THandle * Handle )
|
bool CSelectableCore::Write( THandle * Handle )
|
||||||
{
|
{
|
||||||
|
int BytesWritten = 0;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (!Handle || (Handle->State != csOpen)) {
|
if (!Handle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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 CSelectableCore::WriteToFD( int FD, const char * Data, int Len )
|
||||||
{
|
{
|
||||||
int BytesWritten = 0;
|
int BytesWritten = 0;
|
||||||
@@ -720,7 +853,7 @@ int CSelectableCore::Input( int FD, const char * Data, int Len )
|
|||||||
int BytesWritten = 0;
|
int BytesWritten = 0;
|
||||||
|
|
||||||
// Get File handle
|
// Get File handle
|
||||||
if ((Handle = GetHandle( FD ))) {
|
if ((Handle = GetHandle( "Serial Port" )) || (Handle = GetHandle( "Client" ))) {
|
||||||
// Write to handle
|
// Write to handle
|
||||||
BytesWritten = WriteToFD( Handle->FD, Data, Len );
|
BytesWritten = WriteToFD( Handle->FD, Data, Len );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,16 +38,32 @@ const char ConnectStateName[][15] = { "None", "WaitingToOpen", "Open", "DataWait
|
|||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void SelectConfig( long Timeout );
|
// Previews
|
||||||
void SelectClear();
|
typedef struct SSelectHandle TSelectHandle;
|
||||||
void SelectAdd( int FD, bool Read, bool Write );
|
typedef struct SHandle THandle;
|
||||||
void SelectRemove( int FD, bool Read, bool Write );
|
|
||||||
bool SelectTest();
|
class CSelect;
|
||||||
bool SelectCheck( int FD, bool &Read, bool &Write );
|
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 {
|
struct SHandle {
|
||||||
// Description
|
// Description
|
||||||
char * Name;
|
char * Name;
|
||||||
@@ -74,18 +90,56 @@ struct SHandle {
|
|||||||
timeval InStart;
|
timeval InStart;
|
||||||
long InTimeout; // millisecs
|
long InTimeout; // millisecs
|
||||||
|
|
||||||
|
// List / Tree
|
||||||
THandle * Parent;
|
THandle * Parent;
|
||||||
THandle * Next;
|
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
|
class CSelectableCore : public CFunctionCore
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
// Device Interfaces
|
// FDs
|
||||||
THandle * FirstHandle;
|
THandle * FirstHandle;
|
||||||
|
|
||||||
|
// Select interface
|
||||||
|
CSelect * Select;
|
||||||
|
|
||||||
// Managing File Handles
|
// Managing File Handles
|
||||||
bool RemoveHandle( THandle * Handle );
|
bool RemoveHandle( THandle * Handle );
|
||||||
bool DestroyHandle( THandle * Handle );
|
bool DestroyHandle( THandle * Handle );
|
||||||
@@ -113,7 +167,7 @@ protected:
|
|||||||
|
|
||||||
// Socket Operations
|
// Socket Operations
|
||||||
virtual int OpenServerSocket( THandle * Handle );
|
virtual int OpenServerSocket( THandle * Handle );
|
||||||
//virtual int OpenRemoteClientSocket( THandle * Handle );
|
virtual int OpenRemoteClientSocket( THandle * Handle );
|
||||||
virtual int OpenClientSocket( THandle * Handle );
|
virtual int OpenClientSocket( THandle * Handle );
|
||||||
|
|
||||||
// Mutual Operations
|
// Mutual Operations
|
||||||
@@ -121,6 +175,7 @@ protected:
|
|||||||
virtual bool Read( THandle * Handle );
|
virtual bool Read( THandle * Handle );
|
||||||
virtual bool Write( THandle * Handle );
|
virtual bool Write( THandle * Handle );
|
||||||
|
|
||||||
|
int ReadFromFD( int FD, char * Data, int MaxLen );
|
||||||
int WriteToFD( int FD, const char * Data, int Len );
|
int WriteToFD( int FD, const char * Data, int Len );
|
||||||
|
|
||||||
// Buffer operations
|
// Buffer operations
|
||||||
@@ -128,7 +183,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Life Cycle
|
// Life Cycle
|
||||||
CSelectableCore( const char * Name );
|
CSelectableCore( const char * Name, CSelect * Selector );
|
||||||
~CSelectableCore();
|
~CSelectableCore();
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
@@ -142,7 +197,6 @@ public:
|
|||||||
bool ClearHandle( const char * HandleName );
|
bool ClearHandle( const char * HandleName );
|
||||||
|
|
||||||
virtual int Open( 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( const char * HandleName, bool CloseChildren = false ) { return (Close( GetHandle( HandleName ), CloseChildren )); };
|
||||||
virtual bool Close( int FD, bool CloseChildren = false ) { return (Close( GetHandle( FD ), CloseChildren )); };
|
virtual bool Close( int FD, bool CloseChildren = false ) { return (Close( GetHandle( FD ), CloseChildren )); };
|
||||||
|
|||||||
Reference in New Issue
Block a user