/* * SelectCore.cpp * * Created on: 13 May 2016 * Author: wentzelc */ // Standard C/C++ Libraries /* none */ // redA Libraries #include "ApplicationCore.h" #include "SelectableCore.h" //--------------------------------------------------------------------------- // Global Vars extern char * ProcessName; extern CApplication * Application; //--------------------------------------------------------------------------- // Create Select CSelect::CSelect( long SelectTimeout, EDebugLevel pDebugLevel ) { // Clear List FirstHandle = NULL; // Clear Select sets FD_ZERO( &ReadTestFDS ); FD_ZERO( &WriteTestFDS ); // Reset maximum File Descriptor MaxFD = 0; // Set Timeout SetInterval( &Timeout, SelectTimeout ); // Output Log = Application->Log; LogLevel = pDebugLevel; // Show status if (Log) Log->Message( LogLevel, dlLow, "%s: Selector - Created", ProcessName ); } //--------------------------------------------------------------------------- // Destroy Select CSelect::~CSelect() { TSelectHandle * NextHandle; // Destroy handles while (FirstHandle) { NextHandle = FirstHandle->Next; delete FirstHandle; FirstHandle = NextHandle; } // Show status if (Log) Log->Message( LogLevel, dlLow, "%s: Selector - Destroyed", ProcessName ); return; } //--------------------------------------------------------------------------- bool CSelect::SetLogLevel( EDebugLevel pDebugLevel ) { LogLevel = pDebugLevel; return true; } //--------------------------------------------------------------------------- // Clear Select File Descriptors void CSelect::Clear() { // Clear Select sets FD_ZERO( &ReadTestFDS ); FD_ZERO( &WriteTestFDS ); // Reset maximum File Descriptor MaxFD = 0; } //--------------------------------------------------------------------------- // Add Select File Descriptor void CSelect::Add( int FD, bool Read, bool Write, THandle * Handle, CSelectableBare * Function ) { TSelectHandle ** SelectHandle = NULL; // Check if SelectHandle already exists SelectHandle = &FirstHandle; while (*SelectHandle && ((*SelectHandle)->FD != FD)) { SelectHandle = &((*SelectHandle)->Next); } if (!*SelectHandle) { // Create if not exist *SelectHandle = new TSelectHandle; // Set Parameters (*SelectHandle)->FD = FD; (*SelectHandle)->Handle = Handle; (*SelectHandle)->Function = Function; if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: FD [%d], %s '%s' - Created", ProcessName, FD, ConnectTypeName[((Handle)? Handle->Type : 0)], ((Handle && Handle->Name)? Handle->Name : "") ); } else { if ((*SelectHandle)->Function != Function) { // Old handle for another function, not yet removed, remove from read/write lists Remove( FD, true, true ); if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: FD [%d], %s '%s' - Removed old", ProcessName, FD, ConnectTypeName[((Handle)? Handle->Type : 0)], ((Handle && Handle->Name)? Handle->Name : "") ); } // Overwrite Parameters (*SelectHandle)->Handle = Handle; (*SelectHandle)->Function = Function; } // Add Read select if (Read && !(*SelectHandle)->Read) { (*SelectHandle)->Read = true; FD_SET( FD, &ReadTestFDS ); // Log event if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: FD [%d], %s '%s' - Add Read", ProcessName, FD, ConnectTypeName[((Handle)? Handle->Type : 0)], ((Handle && Handle->Name)? Handle->Name : "") ); } // Add Write Select if (Write && !(*SelectHandle)->Write) { (*SelectHandle)->Write = true; FD_SET( FD, &WriteTestFDS ); // Log event if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: FD [%d], %s '%s' - Add Write", ProcessName, FD, ConnectTypeName[((Handle)? Handle->Type : 0)], ((Handle && Handle->Name)? Handle->Name : "") ); } // Check Maximum File SelectHandle if (MaxFD <= FD) MaxFD = FD+1; } //--------------------------------------------------------------------------- void CSelect::Remove( int FD, bool Read, bool Write ) { TSelectHandle ** SelectHandle = NULL; THandle * Handle = NULL; // Check if SelectHandle already exists SelectHandle = &FirstHandle; while (*SelectHandle && ((*SelectHandle)->FD != FD)) { SelectHandle = &((*SelectHandle)->Next); } // Check if found if (!*SelectHandle) return; Handle = (*SelectHandle)->Handle; // Remove from set for select read check if (Read && (*SelectHandle)->Read) { (*SelectHandle)->Read = false; FD_CLR( FD, &ReadTestFDS); // Log event if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: FD [%d], %s '%s' - Remove Read", ProcessName, FD, ConnectTypeName[((Handle)? Handle->Type : 0)], ((Handle && Handle->Name)? Handle->Name : "") ); } // Remove from set for select write check if (Write && (*SelectHandle)->Write) { (*SelectHandle)->Write = false; FD_CLR( FD, &WriteTestFDS); // Log event if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: FD [%d], %s '%s' - Remove Write", ProcessName, FD, ConnectTypeName[((Handle)? Handle->Type : 0)], ((Handle && Handle->Name)? Handle->Name : "") ); } // Handle will be removed in Test() if both Read & Write flags are false } //--------------------------------------------------------------------------- bool CSelect::Test() { TSelectHandle * Handle = NULL; TSelectHandle ** HandlePtr = NULL; int TestFD = 0; int Events = 0; timeval STimeout = Timeout; // Set Test sets ReadFDS = ReadTestFDS; WriteFDS = WriteTestFDS; // Perform select Events = select( MaxFD, &ReadFDS, &WriteFDS, (fd_set*)NULL, &STimeout ); if (Events < 0) { if (Log) Log->Message( LogLevel, dlHigh, "%s/Selector: Select operation failed", ProcessName ); return false; } // Check all descriptors for events if (Events) { Handle = FirstHandle; while (Handle) { // Check if to remove from list if (!Handle->Read && !Handle->Write) { // Update Maximum Test FD if (Handle->FD == MaxFD-1) { for (TestFD = MaxFD-1; TestFD >= 0; TestFD--) { if (FD_ISSET( TestFD, &ReadTestFDS ) || FD_ISSET( TestFD, &WriteTestFDS )) { break; } } MaxFD = TestFD+1; } // Remove from list HandlePtr = &FirstHandle; while (*HandlePtr && (*HandlePtr != Handle)) HandlePtr = &((*HandlePtr)->Next); *HandlePtr = (*HandlePtr)->Next; // Destroy and go to next delete Handle; Handle = *HandlePtr; continue; } else { // 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)Events; } //---------------------------------------------------------------------------