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
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
PROJECT(lib_redAcore)
|
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)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
// Standard C/C++ Libraries
|
// Standard C/C++ Libraries
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -23,21 +22,15 @@ CFunctionCore::CFunctionCore( const char * FunctionName )
|
|||||||
{
|
{
|
||||||
// Set name
|
// Set name
|
||||||
if (FunctionName) {
|
if (FunctionName) {
|
||||||
Name = (char*)malloc( strlen(FunctionName) );
|
Name = (char*)malloc( strlen(FunctionName)+1 );
|
||||||
strcpy( Name, FunctionName );
|
strcpy( Name, FunctionName );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Name = NULL;
|
Name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In buffer
|
// IO Functions
|
||||||
Buffer = new CBuffer( 20 );
|
|
||||||
OutFunction = NULL;
|
OutFunction = NULL;
|
||||||
|
|
||||||
// Input Timeout
|
|
||||||
InStart.tv_sec = 0;
|
|
||||||
InStart.tv_usec = 0;
|
|
||||||
InTimeout = 100; // millisecs
|
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -47,20 +40,17 @@ CFunctionCore::~CFunctionCore()
|
|||||||
if (Name) {
|
if (Name) {
|
||||||
free( Name );
|
free( Name );
|
||||||
}
|
}
|
||||||
if (Buffer) {
|
|
||||||
delete Buffer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
// Manual Data Input/Output
|
// 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;
|
return 0;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
int CFunctionCore::Output( int OutputID, char * Buffer, int Len )
|
int CFunctionCore::Output( int OutputID, const char * Buffer, int Len )
|
||||||
{
|
{
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,34 +22,21 @@ protected:
|
|||||||
// Function Definition
|
// Function Definition
|
||||||
char * Name;
|
char * Name;
|
||||||
|
|
||||||
// Input/Outputs
|
|
||||||
CBuffer * Buffer;
|
|
||||||
CFunctionCore * OutFunction;
|
CFunctionCore * OutFunction;
|
||||||
|
|
||||||
// Input Timer
|
|
||||||
timeval InStart;
|
|
||||||
long InTimeout; // millisecs
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Life cycle
|
// Life cycle
|
||||||
CFunctionCore( const char * ObjectName );
|
CFunctionCore( const char * ObjectName );
|
||||||
virtual ~CFunctionCore();
|
virtual ~CFunctionCore();
|
||||||
|
|
||||||
// Manual Data Input/Output
|
// Manual Data Input/Output
|
||||||
virtual int Input( int InputID, char * Buffer, int MaxLen );
|
virtual int Input( int InputID, const char * Buffer, int MaxLen );
|
||||||
virtual int Output( int OutputID, char * Buffer, int Len );
|
virtual int Output( int OutputID, const char * Buffer, int Len );
|
||||||
|
|
||||||
// Automated Data Input/Output
|
// Automated Data Input/Output
|
||||||
virtual bool AddInput( int InputID, CFunctionCore * OutFunction, int OutputID );
|
virtual bool AddInput( int InputID, CFunctionCore * OutFunction, int OutputID );
|
||||||
virtual bool AddOutput( int OutputID, CFunctionCore * InFunction, int InputID );
|
virtual bool AddOutput( int OutputID, CFunctionCore * InFunction, int InputID );
|
||||||
virtual bool Process();
|
virtual bool Process() = 0;
|
||||||
|
|
||||||
// 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 );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
303
PortCore.cpp
303
PortCore.cpp
@@ -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 <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
58
PortCore.h
58
PortCore.h
@@ -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_ */
|
|
||||||
@@ -7,14 +7,10 @@
|
|||||||
|
|
||||||
// redA Libraries
|
// redA Libraries
|
||||||
#include "TimingCore.h"
|
#include "TimingCore.h"
|
||||||
#include "SelectCore.h"
|
|
||||||
|
|
||||||
// Standard C/C++ Libraries
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include "SelectableCore.h"
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -67,6 +63,8 @@ void SelectAdd( int FD, bool Read, bool Write )
|
|||||||
|
|
||||||
void SelectRemove( int FD, bool Read, bool Write )
|
void SelectRemove( int FD, bool Read, bool Write )
|
||||||
{
|
{
|
||||||
|
int TestFD = 0;
|
||||||
|
|
||||||
// Remove from set for select read check
|
// Remove from set for select read check
|
||||||
if (Read)
|
if (Read)
|
||||||
FD_CLR( FD, &ReadTestFDS);
|
FD_CLR( FD, &ReadTestFDS);
|
||||||
@@ -76,13 +74,13 @@ void SelectRemove( int FD, bool Read, bool Write )
|
|||||||
FD_CLR( FD, &WriteTestFDS);
|
FD_CLR( FD, &WriteTestFDS);
|
||||||
|
|
||||||
// Check Maximum file handle
|
// Check Maximum file handle
|
||||||
if (FD == MaxFD) {
|
if (FD == MaxFD-1) {
|
||||||
for (int test = MaxFD-1; test >= 0; test--) {
|
for (TestFD = MaxFD-1; TestFD >= 0; TestFD--) {
|
||||||
if (FD_ISSET( test, &ReadTestFDS ) || FD_ISSET( test, &WriteTestFDS )) {
|
if (FD_ISSET( TestFD, &ReadTestFDS ) || FD_ISSET( TestFD, &WriteTestFDS )) {
|
||||||
MaxFD = test+1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MaxFD = TestFD+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@@ -120,4 +118,3 @@ bool SelectCheck( int FD, bool &Read, bool &Write )
|
|||||||
return (Read || Write);
|
return (Read || Write);
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
28
SelectCore.h
28
SelectCore.h
@@ -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_ */
|
|
||||||
924
SelectableCore.cpp
Normal file
924
SelectableCore.cpp
Normal file
@@ -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 <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
176
SelectableCore.h
Normal file
176
SelectableCore.h
Normal file
@@ -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 <string.h>
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 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_ */
|
||||||
379
SocketCore.cpp
379
SocketCore.cpp
@@ -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 <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
66
SocketCore.h
66
SocketCore.h
@@ -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_ */
|
|
||||||
Reference in New Issue
Block a user