Important Updates:

- DataTreeCore:
  - Allow types float, int & bool to be read as strings with GetStr()
- LogCore:
  - Add comments to Logging parameters
- WatchDogCore:
  - Call CSelectableCore::Process() in Process() to manage connect
- SelectableCore:
  - Allow SetSocketHandle() to be called if Handle already set as socket
  - added strlcase() method to convert string to lower case
  - Update Handle structure:
    - renamed Address -> HostName
    - renamed PortNo -> PortName
    - added AddressList for all resolved addresses
    - added AddressInfo for active address
  - Add ResolveAddress() method
    - Domain name and protocol port resolving with GetAddrInfo()
  - JSON updated:
    - domain name can be provided instead of IP address
    - protocol can be specified instead of Port No, e.g. "HTTP" / "SSH"
  - Resolve address before connect, or use next resolved address
This commit is contained in:
Charl Wentzel
2017-07-22 09:40:17 +02:00
parent c32875509d
commit aaf3c59727
6 changed files with 174 additions and 84 deletions

View File

@@ -26,6 +26,7 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
//---------------------------------------------------------------------------
@@ -73,7 +74,7 @@ bool CSelectableCore::LoadConfigData()
char * Name;
char Path[100];
char * Address;
long Port;
char * Port;
// Call Previous load config
CFunctionCore::LoadConfigData();
@@ -103,26 +104,26 @@ bool CSelectableCore::LoadConfigData()
else if (!strcasecmp( Type, "TCPserver" ))
{
Address = (char*)DataTree->GetStr( TempMember, "Socket/Address", NULL ); // Get default Address value
Port = DataTree->GetInt( TempMember, "Socket/Port", 0 ); // Get default Port value
Port = (char*)DataTree->GetStr( TempMember, "Socket/Port", "0" ); // Get default Port value
if ((Name = (char*)DataTree->GetStr( TempMember, "Socket/Name", NULL ))) {
sprintf( Path, "Address/%s/Address", Name );
Address = (char*)DataTree->GetStr( NULL, Path, Address, true ); // Get AddressList Address value
sprintf( Path, "Address/%s/Port", Name );
Port = DataTree->GetInt( NULL, Path, Port, true ); // Get AddressList Port value
Port = (char*)DataTree->GetStr( NULL, Path, Port, true ); // Get AddressList Port value
}
SetSocketHandle( Handle, ctServer, Address, Port, true ); // Assign values
SetSocketHandle( Handle, ctServer, Address, strlcase(Port), true ); // Assign values
}
else if (!strcasecmp( Type, "TCPclient" ))
{
Address = (char*)DataTree->GetStr( TempMember, "Socket/Address", NULL ); // Get default Address value
Port = DataTree->GetInt( TempMember, "Socket/Port", 0 ); // Get default Port value
Port = (char*)DataTree->GetStr( TempMember, "Socket/Port", "0" ); // Get default Port value
if ((Name = (char*)DataTree->GetStr( TempMember, "Socket/Name", NULL ))) {
sprintf( Path, "Address/%s/Address", Name );
Address = (char*)DataTree->GetStr( NULL, Path, Address, true ); // Get AddressList Address value
sprintf( Path, "Address/%s/Port", Name );
Port = DataTree->GetInt( NULL, Path, Port, true ); // Get AddressList Port value
Port = (char*)DataTree->GetStr( NULL, Path, Port, true ); // Get AddressList Port value
}
SetSocketHandle( Handle, ctClient, Address, Port, true ); // Assign values
SetSocketHandle( Handle, ctClient, Address, strlcase(Port), true ); // Assign values
}
else if (!strcasecmp( Type, "ForkPipe" )) {
Address = (char*)DataTree->GetStr( TempMember, "Fork/ExecPath", NULL, true ); // Get default value
@@ -224,8 +225,12 @@ bool CSelectableCore::DestroyHandle( THandle * Handle )
free( Handle->Name );
if (Handle->Path)
free( Handle->Path );
if (Handle->Address)
free( Handle->Address );
if (Handle->HostName)
free( Handle->HostName );
if (Handle->PortName)
free( Handle->PortName );
if (Handle->AddressInfo)
freeaddrinfo( Handle->AddressList );
// Destroy Buffers
if (Handle->InBuffer)
@@ -246,7 +251,7 @@ bool CSelectableCore::DestroyHandle( THandle * Handle )
bool CSelectableCore::SetPortHandle( THandle * Handle, const char * FileName )
{
// Validate
if (!Handle || (Handle->Type != ctNone) || !FileName) {
if (!Handle || ((Handle->Type != ctNone) && (Handle->Type != ctPort)) || !FileName) {
return false;
}
@@ -293,10 +298,11 @@ bool CSelectableCore::SetForkPipeHandle( THandle * Handle, const char * ExecPath
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * Address, const int PortNo, bool KeepAlive )
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, bool KeepAlive )
{
// Validate
if (!Handle || (Handle->Type != ctNone) || !Address || (Type == ctNone) || (Type == ctPort)) {
if (!Handle || ((Handle->Type != ctNone) && (Handle->Type != ctServer) && (Handle->Type != ctClient) && (Handle->Type != ctRemoteClient)) ||
!((Type == ctServer) || (Type == ctClient) || (Type == ctRemoteClient)) || !HostName || !PortName ) {
return false;
}
@@ -304,18 +310,24 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
Handle->Type = Type;
Handle->KeepAlive = KeepAlive;
// Clear Address
if (Handle->Address) {
free( Handle->Address );
}
// Clear HostName & Port Name
if (Handle->HostName)
free( Handle->HostName );
if (Handle->PortName)
free( Handle->PortName );
if (Handle->AddressList)
freeaddrinfo( Handle->AddressList );
// Set Address & Port
Handle->Address = (char*)malloc( strlen(Address)+1 );
strcpy( Handle->Address, Address );
Handle->PortNo = PortNo;
// Set HostName & Port
Handle->HostName = (char*)malloc( strlen(HostName)+1 );
strcpy( Handle->HostName, HostName );
Handle->PortName = (char*)malloc( strlen(PortName)+1 );
strcpy( Handle->PortName, PortName );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
// Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Set as %s [%s:%d]", Name, Handle->Name, ConnectTypeName[Type], Address, PortNo );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Set as %s [%s:%s]", Name, Handle->Name, ConnectTypeName[Type], HostName, PortName );
return true;
}
//---------------------------------------------------------------------------
@@ -332,11 +344,19 @@ bool CSelectableCore::ClearHandle( THandle * Handle )
free( Handle->Path );
Handle->Path = NULL;
}
if (Handle->Address) {
free( Handle->Address );
Handle->Address = NULL;
if (Handle->HostName) {
free( Handle->HostName );
Handle->HostName = NULL;
}
if (Handle->PortName) {
free( Handle->PortName );
Handle->PortName = NULL;
}
if (Handle->AddressList) {
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
}
Handle->PortNo = 0;
// Reset Parameters
Handle->Type = ctNone;
@@ -552,11 +572,60 @@ int CSelectableCore::OpenForkPipe( THandle * Handle )
//---------------------------------------------------------------------------
bool CSelectableCore::ResolveAddress( THandle * Handle )
{
struct addrinfo hints;
int result;
// Check if more addresses
if (Handle->AddressInfo && Handle->AddressInfo->ai_next)
{
// Set next address
Handle->AddressInfo = Handle->AddressInfo->ai_next;
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Use next resolved Address [%s:%s]->[%s:%u]",
Name, Handle->Name, Handle->HostName, Handle->PortName,
inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr),
ntohs(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port) );
return true;
}
// Clear existing address list
if (Handle->AddressList) {
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
}
// Set address specification
memset( &hints, 0, sizeof hints );
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Resolving Host name [%s:%s]...",
Name, Handle->Name, Handle->HostName, Handle->PortName );
// Resolve Host & Port Names
if ((result = getaddrinfo( Handle->HostName, Handle->PortName, &hints, &(Handle->AddressList))) != 0)
{
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)",
Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) );
return false;
}
// Select first address
Handle->AddressInfo = Handle->AddressList;
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Host name resolved [%s:%s]->[%s:%u]",
Name, Handle->Name, Handle->HostName, Handle->PortName,
inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr),
ntohs(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port) );
return true;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenServerSocket( THandle * Handle )
{
socklen_t addr_len;
struct sockaddr_in address;
// Socket options
struct linger ServerLinger_opt;
ServerLinger_opt.l_onoff = 1;
@@ -573,17 +642,19 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
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);
// Resolve Host & Port Names
if (!ResolveAddress( Handle ))
{
// Set Status
ChangeState( Handle, csFailed );
return -1;
}
// Create socket
if ((Handle->FD = socket(AF_INET, SOCK_STREAM, 0)) < 0)
if ((Handle->FD = socket( Handle->AddressInfo->ai_family, Handle->AddressInfo->ai_socktype, Handle->AddressInfo->ai_protocol )) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create TCP Server socket [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create TCP Server socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
@@ -595,7 +666,7 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
(setsockopt( Handle->FD, SOL_SOCKET, SO_REUSEADDR, &Reuse_opt, sizeof(Reuse_opt)) == -1))
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set socket options [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set socket options [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
@@ -610,7 +681,7 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) ))
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set KeepAlive options [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
@@ -622,10 +693,10 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
fcntl( Handle->FD, F_SETFL, flags | O_NONBLOCK );
// Bind socket
if (bind( Handle->FD, (struct sockaddr *)&address, addr_len ) < 0)
if (bind( Handle->FD, Handle->AddressInfo->ai_addr, Handle->AddressInfo->ai_addrlen ) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to bind TCP Server socket [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to bind TCP Server socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
close( Handle->FD );
@@ -638,7 +709,7 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
if (listen( Handle->FD, 5 ) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to listen on TCP Server socket [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to listen on TCP Server socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
close( Handle->FD );
@@ -648,7 +719,7 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
};
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Server binded and listening [%s:%d]", Name, Handle->Name, Handle->Address, Handle->PortNo );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Server binded and listening [%s:%s]", Name, Handle->Name, Handle->HostName, Handle->PortName );
// Add to Select Lists
if (Selector) {
@@ -742,7 +813,7 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
else if (Handle->State == csWaitingtoOpen)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Remote TCP Client connection open [%s]", Name, Handle->Name, Handle->Address );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Remote TCP Client connection open [%s]", Name, Handle->Name, Handle->HostName );
// Update state
ChangeState( Handle, csOpen );
@@ -755,9 +826,6 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
int CSelectableCore::OpenClientSocket( THandle * Handle )
{
socklen_t addr_len;
struct sockaddr_in address;
// Socket options
int KeepAlive_opt = 1;
int TCPidle_opt = 5;
@@ -772,11 +840,19 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
if (Handle->State != csWaitingtoOpen)
{
// Resolve IP Address
if (!ResolveAddress( Handle ))
{
// Set Status
ChangeState( Handle, csFailed );
return -1;
}
// Create File descriptor
if ((Handle->FD = socket( AF_INET, SOCK_STREAM, 0 )) < 0)
if ((Handle->FD = socket( Handle->AddressInfo->ai_family, Handle->AddressInfo->ai_socktype, Handle->AddressInfo->ai_protocol )) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create TCP Client socket [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create TCP Client socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set Status
ChangeState( Handle, csFailed );
@@ -795,7 +871,7 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) ))
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set KeepAlive options [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set State
close( Handle->FD );
@@ -805,15 +881,10 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
}
}
// 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 ))
// Try to connect to address
if (!connect( Handle->FD, Handle->AddressInfo->ai_addr, Handle->AddressInfo->ai_addrlen ))
{
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client connected [%s:%d]", Name, Handle->Name, Handle->Address, Handle->PortNo );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client connected [%s:%s]", Name, Handle->Name, Handle->HostName, Handle->PortName );
// Add to Select Lists
if (Selector) {
@@ -827,7 +898,7 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
else if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EALREADY))
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client waiting to connect [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client waiting to connect [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Add to Select Lists
if (Selector) {
@@ -841,7 +912,7 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
else
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client could not connect [%s:%d] (%s)", Name, Handle->Name, Handle->Address, Handle->PortNo, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client could not connect [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Remove from Select List
if (Selector) {
@@ -907,19 +978,21 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
return false;
// Close Children
if (CloseChildren && (Handle->Type == ctServer)) {
if (CloseChildren && (Handle->Type == ctServer))
{
ChildHandle = FirstHandle;
while (ChildHandle) {
if (ChildHandle->Parent == Handle) {
while (ChildHandle)
{
if (ChildHandle->Parent == Handle)
{
// Close and remove handle
NextHandle = ChildHandle->Next;
// Close
Close( ChildHandle );
// Next Handle
ChildHandle = NextHandle;
} else {
// Next Handle
}
else
{
// Skip Handle
ChildHandle = ChildHandle->Next;
}
}
@@ -946,15 +1019,15 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
break;
case ctServer:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Server %s [%s:%d]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Address, Handle->PortNo );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Server %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
break;
case ctRemoteClient:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Remote TCP Client connection %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Address );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Remote TCP Client connection %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName );
break;
case ctClient:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client connection %s [%s:%d]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Address, Handle->PortNo );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client connection %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
break;
case ctNone:
@@ -969,7 +1042,7 @@ bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
Handle->FD = ((Fail)? Handle->FD : -1);
return true;
}
//---------------------------------------------------------------------------
@@ -1593,3 +1666,4 @@ bool CSelectableCore::BuildArgs( const char * ExecPath, int &Count, char * Args[
return true;
}
//---------------------------------------------------------------------------