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:
@@ -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 );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user