From dcfbd85efabd4c476ce88ba39bb2bcc7b84a6ec0 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Mon, 23 May 2016 14:35:15 +0200 Subject: [PATCH] Major Update: - Merged SelectCore and PortCore into new SelectableCore Single well integrated Class - Rename SelectCore.h to SelectableCore.h - Create new TFileHandle structure for Ports/Sockets - Moved buffer and Input Timeout from FunctionCore to TFileHandle - Moved Read, Write and ProcessBuffer from FunctionCore to TFileHandle Bug Fixes: - malloc correct size for names - Calculate MaxFD correctly when closing FDs --- CMakeLists.txt | 2 +- FunctionCore.cpp | 95 +---- FunctionCore.h | 21 +- PortCore.cpp | 303 --------------- PortCore.h | 58 --- SelectCore.cpp | 17 +- SelectCore.h | 28 -- SelectableCore.cpp | 924 +++++++++++++++++++++++++++++++++++++++++++++ SelectableCore.h | 176 +++++++++ SocketCore.cpp | 379 ------------------- SocketCore.h | 66 ---- 11 files changed, 1116 insertions(+), 953 deletions(-) delete mode 100644 PortCore.cpp delete mode 100644 PortCore.h delete mode 100644 SelectCore.h create mode 100644 SelectableCore.cpp create mode 100644 SelectableCore.h delete mode 100644 SocketCore.cpp delete mode 100644 SocketCore.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8555f8a..752cec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,3 @@ PROJECT(lib_redAcore) -ADD_LIBRARY(redAcore TimingCore.cpp LogCore.cpp BufferCore.cpp FunctionCore.cpp SignalCore.cpp PortCore.cpp SocketCore.cpp SelectCore.cpp) +ADD_LIBRARY(redAcore TimingCore.cpp LogCore.cpp SignalCore.cpp BufferCore.cpp FunctionCore.cpp SelectCore.cpp SelectableCore.cpp) diff --git a/FunctionCore.cpp b/FunctionCore.cpp index 45aefd6..954ca65 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -12,7 +12,6 @@ // Standard C/C++ Libraries #include -#include #include #include @@ -23,21 +22,15 @@ CFunctionCore::CFunctionCore( const char * FunctionName ) { // Set name if (FunctionName) { - Name = (char*)malloc( strlen(FunctionName) ); + Name = (char*)malloc( strlen(FunctionName)+1 ); strcpy( Name, FunctionName ); } else { Name = NULL; } - // In buffer - Buffer = new CBuffer( 20 ); + // IO Functions OutFunction = NULL; - - // Input Timeout - InStart.tv_sec = 0; - InStart.tv_usec = 0; - InTimeout = 100; // millisecs } //--------------------------------------------------------------------------- @@ -47,20 +40,17 @@ CFunctionCore::~CFunctionCore() if (Name) { free( Name ); } - if (Buffer) { - delete Buffer; - } } //--------------------------------------------------------------------------- // Manual Data Input/Output -int CFunctionCore::Input( int InputID, char * Buffer, int MaxLen ) +int CFunctionCore::Input( int InputID, const char * Buffer, int MaxLen ) { return 0; } //--------------------------------------------------------------------------- -int CFunctionCore::Output( int OutputID, char * Buffer, int Len ) +int CFunctionCore::Output( int OutputID, const char * Buffer, int Len ) { return 0; } @@ -81,81 +71,4 @@ bool CFunctionCore::AddOutput( int OutputID, CFunctionCore * InFunction, int Inp } //--------------------------------------------------------------------------- -bool CFunctionCore::Process() -{ - // Misc - long Duration = 0; - - if (Buffer->Len() > 0) - { - // Check duration since last PortIn - Duration = TimePassed( InStart ); - if (Duration > InTimeout) - { - // Process Input - ProcessBuffer( true ); - - // Reset timer - SetInterval( &InStart, 0 ); - } - } - return true; -} -//--------------------------------------------------------------------------- - -// Device Interface -bool CFunctionCore::Read( int fd ) - -{ - int BytesRead = 0; - - // Read File directly into buffer - if (!(BytesRead = Buffer->ReadFromFD( fd ))) - return false; - - // Process Buffer - ProcessBuffer( false ); - - // Reset timer - SetStartTime( &InStart ); - - return true; -} -//--------------------------------------------------------------------------- - -bool CFunctionCore::Write( int fd ) -{ - return false; -} -//--------------------------------------------------------------------------- - -int CFunctionCore::WriteToFD( int FD, char * Data, int Len ) -{ - int BytesWritten = 0; - int TotalWritten = 0; - int DataRemain = 0; - - // Check if buffer created - if ((FD == -1) || !Data) { - return 0; - } - - // Read Data into buffer - DataRemain = (Len == -1)? strlen(Data) : Len; - while (DataRemain) - { - // Read from file descriptor - BytesWritten = write( FD, Data, DataRemain ); - if (BytesWritten <= 0) - break; - - // Update Data Pointers - TotalWritten += BytesWritten; - DataRemain -= BytesWritten; - } - - return TotalWritten; -} -//--------------------------------------------------------------------------- - diff --git a/FunctionCore.h b/FunctionCore.h index ffe2be1..1bd04ca 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -22,13 +22,7 @@ protected: // Function Definition char * Name; - // Input/Outputs - CBuffer * Buffer; - CFunctionCore *OutFunction; - - // Input Timer - timeval InStart; - long InTimeout; // millisecs + CFunctionCore * OutFunction; public: // Life cycle @@ -36,20 +30,13 @@ public: virtual ~CFunctionCore(); // Manual Data Input/Output - virtual int Input( int InputID, char * Buffer, int MaxLen ); - virtual int Output( int OutputID, char * Buffer, int Len ); + virtual int Input( int InputID, const char * Buffer, int MaxLen ); + virtual int Output( int OutputID, const char * Buffer, int Len ); // Automated Data Input/Output virtual bool AddInput( int InputID, CFunctionCore * OutFunction, int OutputID ); virtual bool AddOutput( int OutputID, CFunctionCore * InFunction, int InputID ); - virtual bool Process(); - - // Device Interface - virtual bool Read( int FD ); - virtual bool Write( int FD ); - virtual bool ProcessBuffer( bool Force ) = 0; - - int WriteToFD( int FD, char * Data, int Len ); + virtual bool Process() = 0; }; //--------------------------------------------------------------------------- diff --git a/PortCore.cpp b/PortCore.cpp deleted file mode 100644 index d7fae56..0000000 --- a/PortCore.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * PortCore.cpp - * - * Created on: 13 May 2016 - * Author: wentzelc - */ - -// redA Libraries -#include "PortCore.h" -#include "LogCore.h" - -// Standard C/C++ Libraries -#include -#include -#include -#include - -#include -#include -#include - -//--------------------------------------------------------------------------- - -CPortCore::CPortCore( const char * PortName ) : - CFunctionCore( PortName ) -{ - // Input Markers - InMarkers = NULL; - InMarkerLen = 0; - - // Port File Handle - Handle = -1; -} -//--------------------------------------------------------------------------- - -CPortCore::~CPortCore() -{ - // Destroy pointers - if (InMarkers) { - free( InMarkers ); - } -} -//--------------------------------------------------------------------------- - -bool CPortCore::Open() -{ - // Check if valid port name - if (!Name) { - return false; - } - - // Check if port exits - if (access( Name, F_OK ) != 0) - { - printf( "Port: %s -> Could not find port\n", Name ); - return false; - } - - // Open Port - Handle = open( Name, O_RDWR ); - if (Handle == -1) - { - printf( "Port: %s -> Could not open port\n", Name ); - return false; - } - - // Confirm open - printf( "Port: %s -> Port opened\n", Name ); - return true; -} -//--------------------------------------------------------------------------- - -bool CPortCore::Close() -{ - int result; - - // Check if valid port - if (Handle == -1) { - return true; - } - - // Close port - result = close( Handle ); - if (result) { - printf( "Port: %s -> Port not closed properly\n", Name ); - return false; - } - - // Port closed - printf( "Port: %s -> Port closed\n", Name ); - return true; -} -//--------------------------------------------------------------------------- - -// Configure general input options -bool CPortCore::InputConfig( const long InputTimeout, const char * InputMarkers, int InputMarkerLen ) -{ - InTimeout = InputTimeout; - if (InputMarkerLen && InputMarkers) { - InMarkerLen = InputMarkerLen; - if (InMarkers) { free( InMarkers ); } - InMarkers = (char *)malloc( InMarkerLen ); - memcpy( InMarkers, InputMarkers, InMarkerLen ); - } - else { - InMarkerLen = 0; - InputMarkers = NULL; - } - return true; -} -//--------------------------------------------------------------------------- - -// Set serial port configuration parameters -bool CPortCore::SerialConfig( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ) -{ - struct termios newtio; - int flags = 0; - speed_t _baud = 0; - int mcs = 0; - - // Flush Data from port - tcflush( Handle, TCIFLUSH ); - - // Set Open flags - flags = fcntl( Handle, F_GETFL, 0 ); - fcntl( Handle, F_SETFL, flags & ~O_NDELAY ); - - // Read options - if (tcgetattr( Handle, &newtio ) != 0) - return false; - - // Process the baud rate - switch (Baud) - { - case 921600: _baud = B921600; break; - case 576000: _baud = B576000; break; - case 460800: _baud = B460800; break; - case 230400: _baud = B230400; break; - //case 128000: _baud = B128000; break; - case 115200: _baud = B115200; break; - //case 76800: _baud = B76800; break; - case 57600: _baud = B57600; break; - case 38400: _baud = B38400; break; - //case 28800: _baud = B28800; break; - case 19200: _baud = B19200; break; - //case 14400: _baud = B14400; break; - case 9600: _baud = B9600; break; - case 4800: _baud = B4800; break; - case 2400: _baud = B2400; break; - case 1800: _baud = B1800; break; - case 1200: _baud = B1200; break; - case 600: _baud = B600; break; - case 300: _baud = B300; break; - case 200: _baud = B200; break; - case 150: _baud = B150; break; - case 134: _baud = B134; break; - case 110: _baud = B110; break; - case 75: _baud = B75; break; - case 50: _baud = B50; break; - - default: _baud = B9600; break; - } - - // Set Baud rate - cfsetospeed( &newtio, (speed_t)_baud ); - cfsetispeed( &newtio, (speed_t)_baud ); - - // Generate Mark/Space parity - if ((DataBits == 7) && ((Parity == MARK_PARITY) || (Parity == SPACE_PARITY))) - DataBits = 8; - - // Process the data bits - newtio.c_cflag &= ~CSIZE; - switch (DataBits) - { - case 5: newtio.c_cflag |= CS5; break; - case 6: newtio.c_cflag |= CS6; break; - case 7: newtio.c_cflag |= CS7; break; - case 8: newtio.c_cflag |= CS8; break; - - default: newtio.c_cflag |= CS8; break; - } - - // Set other flags - newtio.c_cflag |= CLOCAL | CREAD; - - // Process Parity - newtio.c_cflag &= ~(PARENB | PARODD); - if (Parity == EVEN_PARITY) - newtio.c_cflag |= PARENB; - else if (Parity == ODD_PARITY) - newtio.c_cflag |= (PARENB | PARODD); - - // Flow Control (for now) - newtio.c_cflag &= ~CRTSCTS; - - // Process Stop Bits - if (StopBits == 2) - newtio.c_cflag |= CSTOPB; - else - newtio.c_cflag &= ~CSTOPB; - - newtio.c_iflag = IGNBRK; - - // Software Flow Control - if (FlowCtrl == SW_FLOWCTRL) - newtio.c_iflag |= IXON | IXOFF; - else - newtio.c_iflag &= ~(IXON | IXOFF | IXANY); - - // Set RAW input & output - newtio.c_lflag=0; - newtio.c_oflag=0; - - // Set wait parameters - newtio.c_cc[VTIME] = Wait; // Blocking: Allow at least a tenth of a second to wait for data - newtio.c_cc[VMIN] = 0; // Non-blocking: Don't set min bytes to receive - - // Set Options (first time) - //tcflush( Handle, TCIFLUSH); - if (tcsetattr( Handle, TCSANOW, &newtio)!=0) - return false; - - // Set Terminal options - ioctl( Handle, TIOCMGET, &mcs); - mcs |= TIOCM_RTS; - ioctl( Handle, TIOCMSET, &mcs); - - // Get Options (again) - if (tcgetattr( Handle, &newtio) != 0) - return false; - - // Process Hardware Flow Control - if (FlowCtrl == HW_FLOWCTRL) - newtio.c_cflag |= CRTSCTS; - else - newtio.c_cflag &= ~CRTSCTS; - - // Set Options (second time) - if (tcsetattr( Handle, TCSANOW, &newtio ) != 0) - { - printf( "Port: %s -> Could not configure port\n", Name ); - return false; - } - - // Port configured - printf( "Port: %s -> Port configured\n", Name ); - return true; -} -//--------------------------------------------------------------------------- - -int CPortCore::Input( int InputID, char * Data, int Len ) -{ - return WriteToFD( Handle, Data, Len ); -} -//--------------------------------------------------------------------------- - -bool CPortCore::ProcessBuffer( bool Force ) -{ - int Pos = 0; - int Len = 0; - char * Data = NULL; - - // Check if buffered data - if (!Buffer->Len()) { - return false; - } - - // Check if forced processed - if (Force) - { - // Show Packet - Len = Buffer->Peek( &Data ); - ShowOutput( "Port In", OUT_NORMAL, Data, Len ); - - // Write buffer to Port - if (OutFunction) - OutFunction->Input( 0, Data, Len ); - - // Clear processed bytes from buffer - Buffer->Clear( Len ); - } - else - { - // Search for end of packet marker - while (Buffer->FindChar( '\n', Pos )) - { - // Show Packet - Len = Buffer->Peek( &Data, 0, Pos+1 ); - ShowOutput( "Port In", OUT_NORMAL, Data, Len ); - - // Write buffer to Port - if (OutFunction) - OutFunction->Input( 0, Data, Len ); - - // Clear processed bytes from buffer - Buffer->Clear( Len ); - } - } - - return true; -} -//--------------------------------------------------------------------------- diff --git a/PortCore.h b/PortCore.h deleted file mode 100644 index df93973..0000000 --- a/PortCore.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * PortCore.h - * - * Created on: 13 May 2016 - * Author: wentzelc - */ - -#ifndef REDACORE_PORTCORE_H_ -#define REDACORE_PORTCORE_H_ - -// redA Libraries -#include "FunctionCore.h" - -// Standard C/C++ Libraries -/* none */ - -//--------------------------------------------------------------------------- - -// Defines required to configure port -#define NO_PARITY 0 -#define ODD_PARITY 1 -#define EVEN_PARITY 2 -#define MARK_PARITY 3 -#define SPACE_PARITY 4 - -#define NO_FLOWCTRL 0 -#define HW_FLOWCTRL 1 -#define SW_FLOWCTRL 2 -//--------------------------------------------------------------------------- - -// Port Core Class -class CPortCore : public CFunctionCore -{ -protected: - // Input Markers - char * InMarkers; - int InMarkerLen; - - // Device Interfaces - int Handle; - -public: - CPortCore( const char * PortName ); - virtual ~CPortCore(); - - bool Open(); - bool Close(); - bool InputConfig( long InputTimeout, const char * InputMarkers, int InputMarkerLen ); - bool SerialConfig( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ); - int GetPortFD() { return Handle; }; - - virtual int Input( int InputID, char * Buffer, int BufLen ); - - virtual bool ProcessBuffer( bool Force ); -}; -//--------------------------------------------------------------------------- - -#endif /* REDACORE_PORTCORE_H_ */ diff --git a/SelectCore.cpp b/SelectCore.cpp index 81d6e6f..2256c13 100644 --- a/SelectCore.cpp +++ b/SelectCore.cpp @@ -7,14 +7,10 @@ // redA Libraries #include "TimingCore.h" -#include "SelectCore.h" - -// Standard C/C++ Libraries #include -#include -#include #include #include +#include "SelectableCore.h" //--------------------------------------------------------------------------- @@ -67,6 +63,8 @@ void SelectAdd( int FD, bool Read, bool Write ) void SelectRemove( int FD, bool Read, bool Write ) { + int TestFD = 0; + // Remove from set for select read check if (Read) FD_CLR( FD, &ReadTestFDS); @@ -76,13 +74,13 @@ void SelectRemove( int FD, bool Read, bool Write ) FD_CLR( FD, &WriteTestFDS); // Check Maximum file handle - if (FD == MaxFD) { - for (int test = MaxFD-1; test >= 0; test--) { - if (FD_ISSET( test, &ReadTestFDS ) || FD_ISSET( test, &WriteTestFDS )) { - MaxFD = test+1; + if (FD == MaxFD-1) { + for (TestFD = MaxFD-1; TestFD >= 0; TestFD--) { + if (FD_ISSET( TestFD, &ReadTestFDS ) || FD_ISSET( TestFD, &WriteTestFDS )) { break; } } + MaxFD = TestFD+1; } } //--------------------------------------------------------------------------- @@ -120,4 +118,3 @@ bool SelectCheck( int FD, bool &Read, bool &Write ) return (Read || Write); } //--------------------------------------------------------------------------- - diff --git a/SelectCore.h b/SelectCore.h deleted file mode 100644 index d346b0a..0000000 --- a/SelectCore.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Select.h - * - * Created on: 13 May 2016 - * Author: wentzelc - */ - -#ifndef REDACORE_SELECTCORE_H_ -#define REDACORE_SELECTCORE_H_ - -// redA Libraries -/* none */ - -// Standard C/C++ Libraries -/* none */ - -//--------------------------------------------------------------------------- - -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 ); - -//--------------------------------------------------------------------------- - -#endif /* REDACORE_SELECTCORE_H_ */ diff --git a/SelectableCore.cpp b/SelectableCore.cpp new file mode 100644 index 0000000..edc6bf9 --- /dev/null +++ b/SelectableCore.cpp @@ -0,0 +1,924 @@ +/* + * CSelectableCore.cpp + * + * Created on: 20 May 2016 + * Author: wentzelc + */ + +// redA Libraries +#include "SelectableCore.h" + +#include "TimingCore.h" +#include "LogCore.h" + +// Standard C/C++ Libraries +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +//--------------------------------------------------------------------------- + +CSelectableCore::CSelectableCore( const char * Name ) : + CFunctionCore( Name ) +{ + // Handles + FirstHandle = NULL; +} +//--------------------------------------------------------------------------- + +CSelectableCore::~CSelectableCore() +{ + THandle * NextHandle = NULL; + + // Destroy File Handles + while (FirstHandle) { + NextHandle = FirstHandle->Next; + DestroyHandle( FirstHandle ); + FirstHandle = NextHandle; + } +} +//--------------------------------------------------------------------------- + +THandle * CSelectableCore::CreateHandle( const char * HandleName ) +{ + THandle ** Handle = NULL; + + // Find Handle by Name or get end of list + Handle = &FirstHandle; + while ( *Handle && strcmp( HandleName, (*Handle)->Name )) + Handle = &((*Handle)->Next); + + // Create if necessary + if (!*Handle) + { + // Create File handle at end of list + *Handle = (THandle*)malloc( sizeof(THandle) ); + memset( *Handle, 0, sizeof(THandle) ); + + // Set name + if (HandleName) { + (*Handle)->Name = (char*)malloc( strlen(HandleName)+1 ); + strcpy( (*Handle)->Name, HandleName ); + } + + // Set File Descriptor + (*Handle)->FD = -1; + } + return *Handle; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::RemoveHandle( THandle * Handle ) +{ + THandle ** HandlePtr = NULL; + + // Validate + if (!Handle || (Handle->Type != ctRemoteClient)) { + return false; + } + + // Find in List + HandlePtr = &FirstHandle; + while (*HandlePtr && (*HandlePtr != Handle)) { + HandlePtr = &((*HandlePtr)->Next); + } + // Remove from list if found + if (*HandlePtr) { + *HandlePtr = (*HandlePtr)->Next; + } + + // Destroy Child handle + DestroyHandle( Handle ); + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::DestroyHandle( THandle * Handle ) +{ + // Validate Handle + if (!Handle) + return false; + + // Clear parameters + if (Handle->Name) + free( Handle->Name ); + if (Handle->FileName) + free( Handle->FileName ); + if (Handle->Address) + free( Handle->Address ); + + // Destroy Buffers + if (Handle->InBuffer) + delete Handle->InBuffer; + if (Handle->OutBuffer) + delete Handle->OutBuffer; + + // Clear Input Markers + if (Handle->InMarker) + free( Handle->InMarker ); + + // Destroy Pointer + free( Handle ); + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::SetPortHandle( const char * HandleName, const char * FileName ) +{ + THandle * Handle = NULL; + + // Validate + if (!FileName) { + return false; + } + + // Search for file handle + if (!(Handle = GetHandle( HandleName ))) { + return false; + } + + // Set Type + Handle->Type = ctPort; + + // Clear File Name + if (Handle->FileName) { + free( Handle->FileName ); + } + + // Set name + Handle->FileName = (char*)malloc( strlen(FileName)+1 ); + strcpy( Handle->FileName, FileName ); + + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::SetSocketHandle( const char * HandleName, EConnectType Type, const char * Address, const int PortNo, bool KeepAlive ) +{ + THandle * Handle = NULL; + + // Validate + if (!Address || (Type == ctNone)) { + return false; + } + + // Search for file handle + if (!(Handle = GetHandle( HandleName ))) { + return false; + } + + // Clear File Name + if (Handle->FileName) { + free( Handle->FileName ); + } + + // Set Type + Handle->Type = Type; + Handle->KeepAlive = KeepAlive; + + // Clear Address + if (Handle->Address) { + free( Handle->Address ); + } + + // Set Address & Port + Handle->Address = (char*)malloc( strlen(Address)+1 ); + strcpy( Handle->Address, Address ); + Handle->PortNo = PortNo; + + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::ClearHandle( const char * HandleName ) +{ + THandle * Handle = NULL; + + // Search for file handle + if (!(Handle = GetHandle( HandleName ))) { + return false; + } + + // Clear File Name + if (Handle->FileName) { + free( Handle->FileName ); + } + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::SetBuffers( const char * HandleName, int InBufSize, int OutBufSize, int InTimeout, const char * InMarker, int InMarkerLen ) +{ + THandle * Handle = NULL; + + // Validate + if (!HandleName) { + return false; + } + + // Get Handle + if (!(Handle = GetHandle( HandleName ))) { + return false;; + } + + // Input Buffer + if (Handle->InBuffer) { + delete Handle->InBuffer; + Handle->InBuffer = NULL; + } + if (InBufSize) { + Handle->InBuffer = new CBuffer( InBufSize ); + } + + // Output Buffer + if (Handle->OutBuffer) { + delete Handle->OutBuffer; + Handle->OutBuffer = NULL; + } + if (OutBufSize) { + Handle->OutBuffer = new CBuffer( OutBufSize ); + } + + // Set Input Timeout + Handle->InTimeout = InTimeout; + + // Set Input Markers + if (InMarkerLen && InMarker) { + Handle->InMarkerLen = InMarkerLen; + Handle->InMarker = (char *)malloc( InMarkerLen+1 ); + memcpy( Handle->InMarker, InMarker, InMarkerLen ); + Handle->InMarker[InMarkerLen] = 0; + } + + return true; +} +//--------------------------------------------------------------------------- + +int CSelectableCore::OpenPort( THandle * Handle ) +{ + // Validate + if (!Handle || (Handle->Type == ctNone)) { + return -1; + } else if (Handle->State == csOpen) { + return Handle->FD; + } + + // Check if port exits + if (access( Handle->FileName, F_OK ) != 0) + { + printf( "Port: %s -> Could not find port\n", Handle->FileName ); + return -1; + } + + // Open Port + Handle->FD = open( Handle->FileName, O_RDWR ); + if (Handle->FD == -1) + { + printf( "Port: %s -> Could not open port\n", Handle->FileName ); + return -1; + } + + // Confirm open + printf( "Port: %s -> Port opened\n", Handle->Name ); + return Handle->FD; +} + +//--------------------------------------------------------------------------- + +int CSelectableCore::OpenServerSocket( THandle * Handle ) +{ + socklen_t addr_len; + struct sockaddr_in address; + + // Socket options + struct linger ServerLinger_opt; + ServerLinger_opt.l_onoff = 1; + ServerLinger_opt.l_linger = 5; + + int Reuse_opt = 1; + int KeepAlive_opt = 1; + int TCPidle_opt = 60; + int TCPint_opt = 15; + int TCPcnt_opt = 3; + + // Validate Handle + if (Handle->Type != ctServer) { + return false; + } + + // Create address + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr(Handle->Address); + address.sin_port = htons(Handle->PortNo); + addr_len = sizeof(address); + + // Create socket + if ((Handle->FD = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf( "Server Socket: %s [%d] -> Failed to create server socket (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) ); + Handle->State = csFailed; + return -1; + }; + + // Configure connection + if ((setsockopt( Handle->FD, SOL_SOCKET, SO_LINGER, &ServerLinger_opt, sizeof(ServerLinger_opt)) == -1) || + (setsockopt( Handle->FD, SOL_SOCKET, SO_REUSEADDR, &Reuse_opt, sizeof(Reuse_opt)) == -1)) + { + printf( "Server Socket: %s [%d] -> Could not set socket options (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) ); + Handle->State = csFailed; + return -1; + } + + // Configure TCP keep alive settings + if (Handle->KeepAlive && + ((setsockopt( Handle->FD, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )) + { + printf( "Server Socket: %s [%d] -> Could not set socket keepalive options (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) ); + Handle->State = csFailed; + return -1; + } + + // Bind socket + if (bind( Handle->FD, (struct sockaddr *)&address, addr_len ) < 0) + { + printf( "Server Socket: %s [%d] -> Failed to bind server to socket (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) ); + close( Handle->FD ); + Handle->State = csFailed; + return -1; + }; + + // Create que for 5 connections + if (listen( Handle->FD, 5 ) < 0) + { + printf( "Server Socket: %s [%d] -> Failed to create server socket listen que (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) ); + close( Handle->FD ); + Handle->State = csFailed; + return -1; +}; + + // Server open + Handle->State = csOpen; + printf( "Server Socket: %s [%d] -> Socket binded and listening\n", Handle->Address, Handle->PortNo ); + return Handle->FD; +} +//--------------------------------------------------------------------------- + +int CSelectableCore::OpenRemoteClientSocket( THandle * Handle ) +{ + THandle ** RemoteClient; + int ClientFD; + char ClientAddress[25]; + + socklen_t addr_len; + struct sockaddr_in address; + + // Validate + if (!Handle) { + return false; + } + + // Check Handle type + if (Handle->Type == ctServer) + { + // Accept connection on current socket + 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) ); + else + printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", (*RemoteClient)->Address, strerror(errno) ); + close( ClientFD ); + return -1; + } + + // Return client address + strcpy( ClientAddress, inet_ntoa(address.sin_addr) ); + + // Get end of client list + RemoteClient = &FirstHandle; + while (*RemoteClient) { + RemoteClient = &((*RemoteClient)->Next); + } + + // Create Remote Client Handle + *RemoteClient = CreateHandle( "Client" ); + SetSocketHandle( "Client", ctRemoteClient, ClientAddress, 0, Handle->KeepAlive ); + SetBuffers( "Client", 20, 0, 50, "\n", 1 ); + (*RemoteClient)->FD = ClientFD; + (*RemoteClient)->Parent = Handle; + (*RemoteClient)->State = csOpen; + + 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 ); + } + return Handle->FD; + } + return -1; +} +//--------------------------------------------------------------------------- + +int CSelectableCore::OpenClientSocket( THandle * Handle ) +{ + socklen_t addr_len; + struct sockaddr_in address; + + // Socket options + int KeepAlive_opt = 1; + int TCPidle_opt = 5; + int TCPcnt_opt = 3; + int TCPint_opt = 2; + + // Create File descriptor + if ((Handle->FD = socket( AF_INET, SOCK_STREAM, 0 )) < 0) + { + printf( "Client Socket: %s [*] -> Failed to create Client Socket (%s)\n", Handle->Address, strerror(errno) ); + return -1; + }; + + // Set Non blocking open + int flags = fcntl( Handle->FD, F_GETFL, 0 ); + fcntl( Handle->FD, F_SETFL, O_NONBLOCK|flags ); + + // Configure TCP keep alive settings + if (Handle->KeepAlive && + ((setsockopt( Handle->FD, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )) + { + printf( "Client Socket: %s -> Could not set socket keepalive options (%s)\n", Handle->Address, strerror(errno) ); + return -1; + } + + // Declare address + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr( Handle->Address ); + address.sin_port = htons( Handle->PortNo ); + addr_len = sizeof(address); + + if (!connect( Handle->FD, (struct sockaddr *)&address, addr_len )) + { + // Set status + Handle->State = csOpen; + return Handle->FD; + } + else if (errno == EINPROGRESS) + { + // Set status + Handle->State = csWaitingtoOpen; + return Handle->FD; + } + else + { + printf( "Client Socket: %s -> Client failed to connect (%s)\n", Handle->Address, strerror(errno) ); + + // Set status + Handle->State = csFailed; + + // Close socket + close( Handle->FD ); + return -1; + } +} +//--------------------------------------------------------------------------- + +int CSelectableCore::Open( const char * HandleName ) +{ + THandle * Handle = NULL; + + // Validate + if (!HandleName || !(Handle = GetHandle( HandleName ))) { + return false; + } + + // Open correctly + switch (Handle->Type) { + case ctPort : + return OpenPort( Handle ); + case ctServer : + return OpenServerSocket( Handle ); + case ctClient : + return OpenClientSocket( Handle ); + case ctRemoteClient : + return OpenRemoteClientSocket( Handle ); + default: + return -1; + } +}; +//--------------------------------------------------------------------------- + +// Delete socket +bool CSelectableCore::Close( THandle * Handle, bool CloseChildren ) +{ + bool Fail; + THandle * ChildHandle = NULL; + THandle * NextHandle = NULL; + + // Close Children + if (CloseChildren && (Handle->Type == ctServer)) { + ChildHandle = FirstHandle; + while (ChildHandle) { + if (ChildHandle->Parent == Handle) { + NextHandle = ChildHandle->Next; + // Close and Destroy handle + Close( ChildHandle ); + RemoveHandle( ChildHandle ); + // Next Handle + ChildHandle = NextHandle; + } else { + // Next Handle + ChildHandle = ChildHandle->Next; + } + } + } + + // Close Handle + Fail = (close( Handle->FD ))? true : false; + Handle->State = ((Fail)? csFailed : csClosed); + Handle->FD = ((Fail)? Handle->FD : -1); + + // Show action + switch (Handle->Type) + { + case ctPort: + printf( "Port: %s -> Port %s\n", Handle->FileName, ((Fail)? "failed" : "closed") ); + break; + + case ctServer: + printf( "Server Socket: %s -> Server %s\n", Handle->Address, ((Fail)? "failed" : "closed") ); + break; + + case ctRemoteClient: + printf( "Remote Client: %s -> Connection to client %s\n", Handle->Address, ((Fail)? "failed" : "closed") ); + break; + + case ctClient: + printf( "Client Socket: %s -> Connection to server %s\n", Handle->Address, ((Fail)? "failed" : "closed") ); + break; + + case ctNone: + default: + printf( "Socket : %s -> Cannot %s socket (invalid socket type)\n", Handle->Address, ((Fail)? "fail" : "close") ); + break; + }; + + return true; +} +//--------------------------------------------------------------------------- + +// Device Interface +bool CSelectableCore::Read( THandle * Handle ) +{ + int BytesRead = 0; + int BytesWaiting = 0; + + // Validate + if (!Handle) { + return false; + } + + // Check for closing event on Socket + if ((Handle->Type == ctRemoteClient) || (Handle->Type == ctClient)) + { + // Check if anything to read + ioctl( Handle->FD, FIONREAD, &BytesWaiting ); + + if (!BytesWaiting) { + // EOF from server (close connection) + Close( Handle ); + RemoveHandle( Handle ); + return false; + } + // Check if socket ready (non-block open not in progress) + else if (Handle->State == csWaitingtoOpen) { + printf( "Socket: %s -> Cannot read from socket in waiting\n", Name ); + return false; + } + } + + // Validate + if (Handle->State != csOpen) { + return false; + } + + // Read File directly into buffer + if (!(BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD ))) + return false; + + // Process Buffer + ProcessBuffer( Handle, false ); + + // Reset timer + SetStartTime( &(Handle->InStart) ); + + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::Write( THandle * Handle ) +{ + // Validate + if (!Handle || (Handle->State != csOpen)) { + return false; + } + + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::Process() +{ + THandle * Handle = NULL; + long Duration = 0; + + // Check all Input buffers + Handle = FirstHandle; + while (Handle) + { + if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) + { + // Check duration since last PortIn + Duration = TimePassed( Handle->InStart ); + if (Duration > Handle->InTimeout) + { + // Process Input + ProcessBuffer( Handle, true ); + + // Reset timer + SetInterval( &(Handle->InStart), 0 ); + } + } + Handle = Handle->Next; + } + return true; +} +//--------------------------------------------------------------------------- + +int CSelectableCore::WriteToFD( int FD, const char * Data, int Len ) +{ + int BytesWritten = 0; + int TotalWritten = 0; + int DataRemain = 0; + + // Check if buffer created + if ((FD == -1) || !Data) { + return 0; + } + + // Read Data into buffer + DataRemain = (Len == -1)? strlen(Data) : Len; + while (DataRemain) + { + // Read from file descriptor + BytesWritten = write( FD, Data, DataRemain ); + if (BytesWritten <= 0) + break; + + // Update Data Pointers + TotalWritten += BytesWritten; + DataRemain -= BytesWritten; + } + + return TotalWritten; +} +//--------------------------------------------------------------------------- + +int CSelectableCore::Input( int FD, const char * Data, int Len ) +{ + THandle * Handle = NULL; + int BytesWritten = 0; + + // Get File handle + if ((Handle = GetHandle( FD ))) { + // Write to handle + BytesWritten = WriteToFD( Handle->FD, Data, Len ); + } + + return BytesWritten; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::ProcessBuffer( THandle * Handle, bool Force ) +{ + int Pos = 0; + int Len = 0; + char * Data = NULL; + + // Check if buffered data + if (!Handle || !Handle->InBuffer->Len()) { + return false; + } + + // Check if forced processed + if (Force) + { + // Show Packet + Len = Handle->InBuffer->Peek( &Data ); + ShowOutput( "Port In", OUT_NORMAL, Data, Len ); + + // Write buffer to Port + if (OutFunction) + OutFunction->Input( 0, Data, Len ); + + // Clear processed bytes from buffer + Handle->InBuffer->Clear( Len ); + } + else + { + // Search for end of packet marker + while (Handle->InBuffer->FindChar( '\n', Pos )) + { + // Show Packet + Len = Handle->InBuffer->Peek( &Data, 0, Pos+1 ); + ShowOutput( "Port In", OUT_NORMAL, Data, Len ); + + // Write buffer to Port + if (OutFunction) + OutFunction->Input( 0, Data, Len ); + + // Clear processed bytes from buffer + Handle->InBuffer->Clear( Len ); + } + } + return true; +} +//--------------------------------------------------------------------------- + +// Set serial port configuration parameters +bool CSelectableCore::SerialConfig( const char *PortName, int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ) +{ + THandle * Handle = NULL; + struct termios newtio; + int flags = 0; + speed_t _baud = 0; + int mcs = 0; + + // Get Handle + if (!(Handle = GetHandle( PortName ))) { + return false; + } + else if (Handle->Type != ctPort) { + return false; + } + + // Flush Data from port + tcflush( Handle->FD, TCIFLUSH ); + + // Set Open flags + flags = fcntl( Handle->FD, F_GETFL, 0 ); + fcntl( Handle->FD, F_SETFL, flags & ~O_NDELAY ); + + // Read options + if (tcgetattr( Handle->FD, &newtio ) != 0) + return false; + + // Process the baud rate + switch (Baud) + { + case 921600: _baud = B921600; break; + case 576000: _baud = B576000; break; + case 460800: _baud = B460800; break; + case 230400: _baud = B230400; break; + //case 128000: _baud = B128000; break; + case 115200: _baud = B115200; break; + //case 76800: _baud = B76800; break; + case 57600: _baud = B57600; break; + case 38400: _baud = B38400; break; + //case 28800: _baud = B28800; break; + case 19200: _baud = B19200; break; + //case 14400: _baud = B14400; break; + case 9600: _baud = B9600; break; + case 4800: _baud = B4800; break; + case 2400: _baud = B2400; break; + case 1800: _baud = B1800; break; + case 1200: _baud = B1200; break; + case 600: _baud = B600; break; + case 300: _baud = B300; break; + case 200: _baud = B200; break; + case 150: _baud = B150; break; + case 134: _baud = B134; break; + case 110: _baud = B110; break; + case 75: _baud = B75; break; + case 50: _baud = B50; break; + + default: _baud = B9600; break; + } + + // Set Baud rate + cfsetospeed( &newtio, (speed_t)_baud ); + cfsetispeed( &newtio, (speed_t)_baud ); + + // Generate Mark/Space parity + if ((DataBits == 7) && ((Parity == MARK_PARITY) || (Parity == SPACE_PARITY))) + DataBits = 8; + + // Process the data bits + newtio.c_cflag &= ~CSIZE; + switch (DataBits) + { + case 5: newtio.c_cflag |= CS5; break; + case 6: newtio.c_cflag |= CS6; break; + case 7: newtio.c_cflag |= CS7; break; + case 8: newtio.c_cflag |= CS8; break; + + default: newtio.c_cflag |= CS8; break; + } + + // Set other flags + newtio.c_cflag |= CLOCAL | CREAD; + + // Process Parity + newtio.c_cflag &= ~(PARENB | PARODD); + if (Parity == EVEN_PARITY) + newtio.c_cflag |= PARENB; + else if (Parity == ODD_PARITY) + newtio.c_cflag |= (PARENB | PARODD); + + // Flow Control (for now) + newtio.c_cflag &= ~CRTSCTS; + + // Process Stop Bits + if (StopBits == 2) + newtio.c_cflag |= CSTOPB; + else + newtio.c_cflag &= ~CSTOPB; + + newtio.c_iflag = IGNBRK; + + // Software Flow Control + if (FlowCtrl == SW_FLOWCTRL) + newtio.c_iflag |= IXON | IXOFF; + else + newtio.c_iflag &= ~(IXON | IXOFF | IXANY); + + // Set RAW input & output + newtio.c_lflag=0; + newtio.c_oflag=0; + + // Set wait parameters + newtio.c_cc[VTIME] = Wait; // Blocking: Allow at least a tenth of a second to wait for data + newtio.c_cc[VMIN] = 0; // Non-blocking: Don't set min bytes to receive + + // Set Options (first time) + //tcflush( Handle->FD, TCIFLUSH); + if (tcsetattr( Handle->FD, TCSANOW, &newtio)!=0) + return false; + + // Set Terminal options + ioctl( Handle->FD, TIOCMGET, &mcs); + mcs |= TIOCM_RTS; + ioctl( Handle->FD, TIOCMSET, &mcs); + + // Get Options (again) + if (tcgetattr( Handle->FD, &newtio) != 0) + return false; + + // Process Hardware Flow Control + if (FlowCtrl == HW_FLOWCTRL) + newtio.c_cflag |= CRTSCTS; + else + newtio.c_cflag &= ~CRTSCTS; + + // Set Options (second time) + if (tcsetattr( Handle->FD, TCSANOW, &newtio ) != 0) + { + printf( "Port: %s -> Could not configure port\n", Name ); + return false; + } + + // Port configured + printf( "Port: %s -> Port configured\n", Name ); + return true; +} +//--------------------------------------------------------------------------- diff --git a/SelectableCore.h b/SelectableCore.h new file mode 100644 index 0000000..6a84a2c --- /dev/null +++ b/SelectableCore.h @@ -0,0 +1,176 @@ +/* + * Select.h + * + * Created on: 13 May 2016 + * Author: wentzelc + */ + +#ifndef REDACORE_SELECTABLECORE_H_ +#define REDACORE_SELECTABLECORE_H_ + +// redA Libraries +#include "FunctionCore.h" + +// Standard C/C++ Libraries +#include + +//--------------------------------------------------------------------------- + +// Types required for connections +typedef enum { ctNone = 0, ctPort = 1, ctServer = 2, ctRemoteClient = 3, ctClient = 4 } EConnectType; +const char ConnectTypeName[][15] = { "None", "Port", "Server", "RemoteClient", "Client" }; + +typedef enum { csNone = 0, csWaitingtoOpen = 1, csOpen = 2, csDataWaiting = 3, csClosed = 4, csFailed = 5 } EConnectState; +const char ConnectStateName[][15] = { "None", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" }; + +//--------------------------------------------------------------------------- + +// Defines required to configure port +#define NO_PARITY 0 +#define ODD_PARITY 1 +#define EVEN_PARITY 2 +#define MARK_PARITY 3 +#define SPACE_PARITY 4 + +#define NO_FLOWCTRL 0 +#define HW_FLOWCTRL 1 +#define SW_FLOWCTRL 2 + +//--------------------------------------------------------------------------- + +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 ); + +//--------------------------------------------------------------------------- + +typedef struct SHandle THandle; +struct SHandle { + // Description + char * Name; + EConnectType Type; + + char * FileName; + + char * Address; + int PortNo; + bool KeepAlive; + + int FD; + EConnectState State; + + // Buffers + CBuffer * InBuffer; + CBuffer * OutBuffer; + + // Input Markers + char * InMarker; + int InMarkerLen; + + // Input Timer + timeval InStart; + long InTimeout; // millisecs + + THandle * Parent; + THandle * Next; +}; + +//--------------------------------------------------------------------------- + +class CSelectableCore : public CFunctionCore +{ +protected: + // Device Interfaces + THandle * FirstHandle; + + // Managing File Handles + bool RemoveHandle( THandle * Handle ); + bool DestroyHandle( THandle * Handle ); + + // Finding files + inline THandle * GetHandle( const char * HandleName ) + { + if (!HandleName) return NULL; + THandle * Handle = FirstHandle; + while ( Handle && strcmp( HandleName, Handle->Name )) + Handle = Handle->Next; + return Handle; + } + inline THandle * GetHandle( int FD ) + { + if (FD < 0) return NULL; + THandle * Handle = FirstHandle; + while ( Handle && (FD != Handle->FD)) + Handle = Handle->Next; + return Handle; + } + + // Port Operations + virtual int OpenPort( THandle * Handle ); + + // Socket Operations + virtual int OpenServerSocket( THandle * Handle ); + //virtual int OpenRemoteClientSocket( THandle * Handle ); + virtual int OpenClientSocket( THandle * Handle ); + + // Mutual Operations + virtual bool Close( THandle * Handle, bool CloseChildren = false ); + virtual bool Read( THandle * Handle ); + virtual bool Write( THandle * Handle ); + + int WriteToFD( int FD, const char * Data, int Len ); + + // Buffer operations + virtual bool ProcessBuffer( THandle * Handle, bool Force ); + +public: + // Life Cycle + CSelectableCore( const char * Name ); + ~CSelectableCore(); + + // Configuration + THandle * CreateHandle( const char * HandleName ); + bool SetBuffers( const char * HandleName, int InBufSize, int OutBufSize, int InTimeout, const char * InMarker, int InMarkerLen ); + bool SerialConfig( const char * HandleName, int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ); + + // Device Interface + bool SetPortHandle( const char * HandleName, const char * FileName ); + bool SetSocketHandle( const char * HandleName, EConnectType Type, const char * Address, const int PortNo, bool KeepAlive ); + 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 )); }; + + virtual bool Read( const char * HandleName ) { return (Read( GetHandle( HandleName ))); }; + virtual bool Read( int FD ) { return (Read( GetHandle( FD ))); }; + + virtual bool Write( const char * HandleName ) { return (Write( GetHandle( HandleName ))); }; + virtual bool Write( int FD ) { return (Write( GetHandle( FD ))); }; + + inline int GetFD( const char * HandleName ) { + THandle * Handle = GetHandle( HandleName ); + return ((Handle)? Handle->FD : -1); + }; + inline EConnectType GetType( const char * HandleName ) { + THandle * Handle = GetHandle( HandleName ); + return ((Handle)? Handle->Type : ctNone); + }; + inline EConnectState GetState( const char * HandleName ) { + THandle * Handle = GetHandle( HandleName ); + return ((Handle)? Handle->State : csNone); + }; + + // Function Interface + virtual int Input( int FD, const char * Buffer, int BufLen ); + virtual bool Process(); +}; + +//--------------------------------------------------------------------------- + +#endif /* REDACORE_SELECTABLECORE_H_ */ diff --git a/SocketCore.cpp b/SocketCore.cpp deleted file mode 100644 index 4bcd35a..0000000 --- a/SocketCore.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* - * SocketCore.h - * - * Created on: 13 May 2016 - * Author: wentzelc - */ - -// redA Libraries -#include "TimingCore.h" -#include "SocketCore.h" -#include "LogCore.h" - -// Standard C/C++ Libraries -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -//--------------------------------------------------------------------------- - -CSocketCore::CSocketCore( const char * ServerName ) : - CFunctionCore( ServerName ) -{ - ServerAddress[0] = 0; - PortNo = 0; - ClientAddress[0] = 0; - - ServerHandle = -1; - ServerState = ssNone; - - ClientHandle = -1; - ClientState = ssNone; -} -//--------------------------------------------------------------------------- - -CSocketCore::~CSocketCore() -{ -} -//--------------------------------------------------------------------------- - -int CSocketCore::OpenTCPserverSocket( const char *pAddress, int pPortNo, bool KeepAlive ) -{ - socklen_t addr_len; - struct sockaddr_in address; - - strcpy( ServerAddress, pAddress ); - PortNo = pPortNo; - - // Socket options - struct linger ServerLinger_opt; - ServerLinger_opt.l_onoff = 1; - ServerLinger_opt.l_linger = 5; - - int Reuse_opt = 1; - int KeepAlive_opt = 1; - int TCPidle_opt = 60; - int TCPint_opt = 15; - int TCPcnt_opt = 3; - - // Create address - address.sin_family = AF_INET; - address.sin_addr.s_addr = inet_addr(ServerAddress); - address.sin_port = htons(PortNo); - addr_len = sizeof(address); - - // Set default socket state - ServerState = ssNone; - - // Create socket - if ((ServerHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - printf( "Server Socket: %s [%d] -> Failed to create server socket (%s)\n", Name, PortNo, strerror(errno) ); - ServerState = ssFailed; - return -1; - }; - - // Configure connection - if ((setsockopt( ServerHandle, SOL_SOCKET, SO_LINGER, &ServerLinger_opt, sizeof(ServerLinger_opt)) == -1) || - (setsockopt( ServerHandle, SOL_SOCKET, SO_REUSEADDR, &Reuse_opt, sizeof(Reuse_opt)) == -1)) - { - printf( "Server Socket: %s [%d] -> Could not set socket options (%s)\n", Name, PortNo, strerror(errno) ); - ServerState = ssFailed; - return -1; - } - - // Configure TCP keep alive settings - if (KeepAlive && - ((setsockopt( ServerHandle, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || - (setsockopt( ServerHandle, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || - (setsockopt( ServerHandle, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || - (setsockopt( ServerHandle, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )) - { - printf( "Server Socket: %s [%d] -> Could not set socket keepalive options (%s)\n", Name, PortNo, strerror(errno) ); - ServerState = ssFailed; - return -1; - } - - // Bind socket - if (bind( ServerHandle, (struct sockaddr *)&address, addr_len ) < 0) - { - printf( "Server Socket: %s [%d] -> Failed to bind server to socket (%s)\n", Name, PortNo, strerror(errno) ); - close( ServerHandle ); - ServerState = ssFailed; - return -1; - }; - - // Create que for 5 connections - if (listen( ServerHandle, 5 ) < 0) - { - printf( "Server Socket: %s [%d] -> Failed to create server socket listen que (%s)\n", Name, PortNo, strerror(errno) ); - close( ServerHandle ); - ServerState = ssFailed; - return -1; - }; - - // Server open - ServerState = ssOpen; - printf( "Server Socket: %s [%d] -> Socket binded and listening\n", Name, PortNo ); - return ServerHandle; -} -//--------------------------------------------------------------------------- - -int CSocketCore::OpenTCPinClientSocket() -{ - socklen_t addr_len; - struct sockaddr_in address; - - - // Set default socket state - if (ClientHandle == -1) - { - // Accept connection on current socket - addr_len = sizeof( address ); - if ((ClientHandle = accept( ServerHandle, (struct sockaddr *)&address, &addr_len)) == -1) - { - if (errno == EWOULDBLOCK) - printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", Name, strerror(errno) ); - else - printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", Name, strerror(errno) ); - close( ClientHandle ); - return -1; - } - - // Return client address - strcpy( ClientAddress, inet_ntoa(address.sin_addr) ); - ClientState = ssOpen; - printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Name, ClientAddress ); - } - else if (ClientState == ssWaitingtoOpen) - { - // Clear non blocking flag - int flags = fcntl( ClientHandle, F_GETFL, 0 ); - fcntl( ClientHandle, F_SETFL, (!O_NONBLOCK)&flags ); - - // Log event - printf( "Socket: %s -> Client now connected to server (%s)\n", Name, ServerAddress ); - - // Trigger handler & set new state - ClientState = ssOpen; - } - - return ClientHandle; -} -//--------------------------------------------------------------------------- - -int CSocketCore::OpenTCPoutClientSocket( const char *pAddress, int pPortNo, bool KeepAlive ) -{ - socklen_t addr_len; - struct sockaddr_in address; - - strcpy( ServerAddress, pAddress ); - PortNo = pPortNo; - - // Socket options - int KeepAlive_opt = 1; - int TCPidle_opt = 5; - int TCPcnt_opt = 3; - int TCPint_opt = 2; - - // Set default socket state - ClientState = ssNone; - - // Create File descriptor - if ((ClientHandle = socket( AF_INET, SOCK_STREAM, 0 )) < 0) - { - printf( "Client Socket: %s [*] -> Failed to create Client Socket (%s)\n", Name, strerror(errno) ); - return -1; - }; - - // Set Non blocking open - int flags = fcntl( ClientHandle, F_GETFL, 0 ); - fcntl( ClientHandle, F_SETFL, O_NONBLOCK|flags ); - - // Configure TCP keep alive settings - if (KeepAlive && - ((setsockopt( ClientHandle, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) || - (setsockopt( ClientHandle, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) || - (setsockopt( ClientHandle, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) || - (setsockopt( ClientHandle, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) )) - { - printf( "Client Socket: %s -> Could not set socket keepalive options (%s)\n", Name, strerror(errno) ); - return -1; - } - - // Declare address - address.sin_family = AF_INET; - address.sin_addr.s_addr = inet_addr( ServerAddress ); - address.sin_port = htons(PortNo); - addr_len = sizeof(address); - - if (!connect( ClientHandle, (struct sockaddr *)&address, addr_len )) - { - // Set status - ClientState = ssOpen; - return ClientHandle; - } - else if (errno == EINPROGRESS) - { - // Set status - ClientState = ssWaitingtoOpen; - return ClientHandle; - } - else - { - printf( "Client Socket: %s -> Client failed to connect (%s)\n", Name, strerror(errno) ); - - // Set status - ClientState = ssFailed; - - // Close socket - close( ClientHandle ); - return -1; - } -} -//--------------------------------------------------------------------------- - -// Delete socket -bool CSocketCore::CloseTCPSocket( ESockConnectType SocketType ) -{ - bool Fail; - - if (SocketType == ctServer) { - Fail = (close( ServerHandle ))? true : false; - ServerState = ((Fail)? ssFailed : ssClosed); - } - else { - Fail = (close( ClientHandle ))? true : false; - ClientState = ((Fail)? ssFailed : ssClosed); - } - - // Show action - switch (SocketType) - { - case ctServer: - printf( "Server Socket: %s -> Server %s\n", Name, ((Fail)? "failed" : "closed") ); - break; - - case ctRemoteClient: - printf( "Remote Client: %s -> Connection to client %s\n", Name, ((Fail)? "failed" : "closed") ); - break; - - case ctClient: - printf( "Client Socket: %s -> Connection to server %s\n", Name, ((Fail)? "failed" : "closed") ); - break; - - case ctNone: - default: - printf( "Socket : %s -> Cannot %s socket (invalid socket type)\n", Name, ((Fail)? "fail" : "close") ); - break; - }; - - return true; -} -//--------------------------------------------------------------------------- - -int CSocketCore::Input( int InputID, char * Data, int Len ) -{ - return WriteToFD( ClientHandle, Data, Len ); -} -//--------------------------------------------------------------------------- - -bool CSocketCore::Read( int FD ) -{ - int SockBytesRead = 0; - int SockBytesWaiting = 0; - - // Check if anything to read - ioctl( FD, FIONREAD, &SockBytesWaiting ); - - // Test for close event - if (!SockBytesWaiting) - { - // EOF from server (close connection) - CloseTCPSocket( ctRemoteClient ); - ClientHandle = -1; - return false; - } - // Check if socket ready (non-block open not in progress) - else if (ClientState == ssWaitingtoOpen) - { - printf( "Socket: %s -> Cannot read from socket in waiting\n", Name ); - SockBytesWaiting = 0; - } - // Handle incoming data - else - { - // Read data from socket - if (!(SockBytesRead = Buffer->ReadFromFD( FD, SockBytesWaiting ))) { - return false; - } - - // Process Buffer - ProcessBuffer( false ); - - // Start timer - SetStartTime( &InStart ); - } - return true; -} -//--------------------------------------------------------------------------- - -bool CSocketCore::ProcessBuffer( bool Force ) -{ - int Pos = 0; - int Len = 0; - char * Data = NULL; - - // Check if buffered data - if (!Buffer->Len()) { - return false; - } - - // Check if forced processed - if (Force) - { - // Show Packet - Len = Buffer->Peek( &Data ); - ShowOutput( "Port In", OUT_NORMAL, Data, Len ); - - // Write buffer to Port - if (OutFunction) - OutFunction->Input( 0, Data, Len ); - - // Clear processed bytes from buffer - Buffer->Clear( Len ); - } - else - { - // Search for end of packet marker - while (Buffer->FindChar( '\n', Pos )) - { - // Show Packet - Len = Buffer->Peek( &Data, 0, Pos+1 ); - ShowOutput( "Port In", OUT_NORMAL, Data, Len ); - - // Write buffer to Port - if (OutFunction) - OutFunction->Input( 0, Data, Len ); - - // Clear processed bytes from buffer - Buffer->Clear( Len ); - } - } - - return true; -} -//--------------------------------------------------------------------------- - diff --git a/SocketCore.h b/SocketCore.h deleted file mode 100644 index 834f4ab..0000000 --- a/SocketCore.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SocketCore.h - * - * Created on: 13 May 2016 - * Author: wentzelc - */ - -#ifndef REDACORE_SOCKETCORE_H_ -#define REDACORE_SOCKETCORE_H_ - -// redA Libraries -#include "FunctionCore.h" - -// Standard C/C++ Libraries -/* none */ - -//--------------------------------------------------------------------------- - -// Types required for sockets -typedef enum { ctNone = 0, ctServer = 1, ctRemoteClient = 2, ctClient = 3 } ESockConnectType; -const char SockConnectTypeName[][15] = { "None", "Server", "RemoteClient", "Client" }; - -typedef enum { ssNone = 0, ssWaitingtoOpen = 1, ssOpen = 2, ssDataWaiting = 3, ssClosed = 4, ssFailed = 5 } ESocketState; -const char SocketStateName[][15] = { "None", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" }; -//--------------------------------------------------------------------------- - -// Port Core Class -class CSocketCore : public CFunctionCore -{ -protected: - char ServerAddress[25]; - int PortNo; - char ClientAddress[25]; - - int ServerHandle; - ESocketState ServerState; - - int ClientHandle; - ESocketState ClientState; - -public: - // Life Cycle - CSocketCore( const char * ServerName ); - virtual ~CSocketCore(); - - // Socket Functions - int OpenTCPserverSocket( const char *ServerAddress, int PortNo, bool KeepAlive ); - int OpenTCPinClientSocket(); - int OpenTCPoutClientSocket( const char *ServerAddress, int PortNo, bool KeepAlive ); - - ESocketState GetServerState(); - ESocketState GetClientState(); - - bool CloseTCPSocket( ESockConnectType SocketType ); - - int GetServerFD() { return ServerHandle; }; - int GetClientFD() { return ClientHandle; }; - - virtual int Input( int InputID, char * Buffer, int BufLen ); - - virtual bool Read( int FD ); - virtual bool ProcessBuffer( bool Force ); -}; -//--------------------------------------------------------------------------- - -#endif /* REDACORE_SOCKETCORE_H_ */