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

@@ -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,31 +425,30 @@ 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 );
(*RemoteClient)->FD = ClientFD;
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 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 );
RemoveHandle( 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;
}
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 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 );
}