Important Update:

- Add Resolve Delay, allow time delay before resolving address
  Allow completion of other actions before blocking all to getaddr()
- Remove Handle->KeepAlive, assume always true
This commit is contained in:
Charl Wentzel
2017-12-10 21:39:55 +02:00
parent 75dec370f7
commit 4ec1dc6cd7
2 changed files with 82 additions and 56 deletions

View File

@@ -77,6 +77,7 @@ bool CSelectableCore::LoadConfigData()
char * FlowCtrlText;
short Parity;
short FlowCtrl;
long Delay;
// Call Previous load config
CFunctionCore::LoadConfigData();
@@ -96,11 +97,13 @@ bool CSelectableCore::LoadConfigData()
Type = (char*)DataTree->GetStr( TempMember, "Type", "TCPclient", true );
if (!strcasecmp( Type, "Serial" ))
{
Address = (char*)DataTree->GetStr( TempMember, "Port/Address", NULL ); // Get default value
if ((Name = (char*)DataTree->GetStr( TempMember, "Port/Name", NULL ))) {
sprintf( Path, "Address/%s/Address", Name );
Address = (char*)DataTree->GetStr( NULL, Path, Address, true ); // Get address list value
}
else {
Address = (char*)DataTree->GetStr( TempMember, "Port/Address", NULL, true ); // Get default value
}
SetSerialHandle( Handle, Address );
// Update configuration if specified
@@ -133,36 +136,44 @@ bool CSelectableCore::LoadConfigData()
}
else if (!strcasecmp( Type, "LinePrinter" ))
{
Address = (char*)DataTree->GetStr( TempMember, "Port/Address", NULL ); // Get default value
if ((Name = (char*)DataTree->GetStr( TempMember, "Port/Name", NULL ))) {
sprintf( Path, "Address/%s/Address", Name );
Address = (char*)DataTree->GetStr( NULL, Path, Address, true ); // Get address list value
}
else {
Address = (char*)DataTree->GetStr( TempMember, "Port/Address", NULL, true ); // Get default value
}
SetLinePrinterHandle( Handle, Address );
}
else if (!strcasecmp( Type, "TCPserver" ))
{
Address = (char*)DataTree->GetStr( TempMember, "Socket/Address", NULL ); // Get default Address 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 = (char*)DataTree->GetStr( NULL, Path, Port, true ); // Get AddressList Port value
}
SetSocketHandle( Handle, ctServer, Address, strlcase(Port), true ); // Assign values
else {
Address = (char*)DataTree->GetStr( TempMember, "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)DataTree->GetStr( TempMember, "Socket/Port", "0", true ); // Get default Port value
}
Delay = DataTree->GetInt( TempMember, "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctServer, Address, strlcase(Port), Delay );
}
else if (!strcasecmp( Type, "TCPclient" ))
{
Address = (char*)DataTree->GetStr( TempMember, "Socket/Address", NULL ); // Get default Address 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 = (char*)DataTree->GetStr( NULL, Path, Port, true ); // Get AddressList Port value
}
SetSocketHandle( Handle, ctClient, Address, strlcase(Port), true ); // Assign values
else {
Address = (char*)DataTree->GetStr( TempMember, "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)DataTree->GetStr( TempMember, "Socket/Port", "0", true ); // Get default Port value
}
Delay = DataTree->GetInt( TempMember, "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctClient, Address, strlcase(Port), Delay );
}
else if (!strcasecmp( Type, "ForkPipe" )) {
Address = (char*)DataTree->GetStr( TempMember, "Fork/ExecPath", NULL, true ); // Get default value
@@ -383,7 +394,7 @@ bool CSelectableCore::SetForkPipeHandle( THandle * Handle, const char * ExecPath
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, bool KeepAlive )
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, long ResolveDelay )
{
// Validate
if (!Handle || ((Handle->Type != ctNone) && (Handle->Type != ctServer) && (Handle->Type != ctClient) && (Handle->Type != ctRemoteClient)) ||
@@ -392,8 +403,8 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
}
// Set Type
Handle->Type = Type;
Handle->KeepAlive = KeepAlive;
Handle->Type = Type;
Handle->ResolveDelay = ResolveDelay;
// Clear HostName & Port Name
if (Handle->HostName)
@@ -717,7 +728,7 @@ int CSelectableCore::OpenForkPipe( THandle * Handle )
//---------------------------------------------------------------------------
bool CSelectableCore::ResolveAddress( THandle * Handle )
bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
{
struct addrinfo hints;
int result;
@@ -762,11 +773,21 @@ bool CSelectableCore::ResolveAddress( THandle * Handle )
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Resolving Host name [%s:%s]...",
Name, Handle->Name, Handle->HostName, Handle->PortName );
// Should address be resolved later during process()
if (DelayResolve)
{
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Delay resolving of Host Name [%s:%s]",
Name, Handle->Name, Handle->HostName, Handle->PortName );
ChangeState( Handle, csOpenRequest );
return false;
}
// 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) );
ChangeState( Handle, csFailed );
return false;
}
@@ -780,6 +801,7 @@ bool CSelectableCore::ResolveAddress( THandle * Handle )
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
ChangeState( Handle, csFailed );
return false;
}
@@ -792,7 +814,7 @@ bool CSelectableCore::ResolveAddress( THandle * Handle )
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenServerSocket( THandle * Handle )
int CSelectableCore::OpenServerSocket( THandle * Handle, bool DelayResolve )
{
// Socket options
struct linger ServerLinger_opt;
@@ -811,12 +833,8 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
}
// Resolve Host & Port Names
if (!ResolveAddress( Handle ))
{
// Set Status
ChangeState( Handle, csFailed );
if (!ResolveAddress( Handle, DelayResolve ))
return -1;
}
// Create socket
if ((Handle->FD = socket( Handle->AddressInfo->ai_family, Handle->AddressInfo->ai_socktype, Handle->AddressInfo->ai_protocol )) < 0)
@@ -842,11 +860,10 @@ int CSelectableCore::OpenServerSocket( THandle * Handle )
}
// 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) ))
if ((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) )
{
// Log Event
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) );
@@ -953,7 +970,7 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
// Create Remote Client Handle
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
*RemoteClient = CreateHandle( ClientName, false );
if (!SetSocketHandle( *RemoteClient, ctRemoteClient, ClientAddress, ClientPort, Handle->KeepAlive )) {
if (!SetSocketHandle( *RemoteClient, ctRemoteClient, ClientAddress, ClientPort, 0 )) {
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Server failed to configure Remote TCP Client connection (%s)", Name, Handle->Name, strerror(errno) );
return -1;
}
@@ -1003,7 +1020,7 @@ int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenClientSocket( THandle * Handle )
int CSelectableCore::OpenClientSocket( THandle * Handle, bool DelayResolve )
{
// Socket options
int KeepAlive_opt = 1;
@@ -1020,12 +1037,8 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
if (Handle->State != csWaitingtoOpen)
{
// Resolve IP Address
if (!ResolveAddress( Handle ))
{
// Set Status
ChangeState( Handle, csFailed );
if (!ResolveAddress( Handle, DelayResolve ))
return -1;
}
// Create File descriptor
if ((Handle->FD = socket( Handle->AddressInfo->ai_family, Handle->AddressInfo->ai_socktype, Handle->AddressInfo->ai_protocol )) < 0)
@@ -1043,11 +1056,10 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
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) ))
if ((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) )
{
// Log Event
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) );
@@ -1110,7 +1122,7 @@ int CSelectableCore::OpenClientSocket( THandle * Handle )
}
//---------------------------------------------------------------------------
int CSelectableCore::Open( THandle * Handle )
int CSelectableCore::Open( THandle * Handle, bool DelayResolve )
{
int FD = -1;
@@ -1131,10 +1143,10 @@ int CSelectableCore::Open( THandle * Handle )
FD = OpenForkPipe( Handle );
break;
case ctServer :
FD = OpenServerSocket( Handle );
FD = OpenServerSocket( Handle, DelayResolve );
break;
case ctClient :
FD = OpenClientSocket( Handle );
FD = OpenClientSocket( Handle, DelayResolve );
break;
case ctRemoteClient :
FD = OpenRemoteClientSocket( Handle );
@@ -1278,7 +1290,7 @@ bool CSelectableCore::Read( THandle * Handle )
if (Handle->Type == ctRemoteClient) {
OpenRemoteClientSocket( Handle );
} else if (Handle->Type == ctClient) {
OpenClientSocket( Handle );
OpenClientSocket( Handle, true );
}
// Reset Timer (for auto-close)
SetStartTime( &(Handle->LastAction) );
@@ -1378,7 +1390,7 @@ bool CSelectableCore::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Attempt to re-open port
Open( Handle );
Open( Handle, true );
}
}
@@ -1391,7 +1403,7 @@ bool CSelectableCore::Write( THandle * Handle )
if (Handle->Type == ctRemoteClient) {
OpenRemoteClientSocket( Handle );
} else if (Handle->Type == ctClient) {
OpenClientSocket( Handle );
OpenClientSocket( Handle, true );
}
// Reset Timer (for auto-close)
SetStartTime( &(Handle->LastAction) );
@@ -1623,10 +1635,14 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Complete opening process
Open( Handle );
Open( Handle, true );
// Check if Handle is open
if (Handle->State == csWaitingtoOpen) {
if (Handle->State == csOpenRequest) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle", Name, Handle->Name );
return 0;
}
else if (Handle->State == csWaitingtoOpen) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Input rejected, Waiting to open (auto-managed) Handle", Name, Handle->Name );
return 0;
}
@@ -1727,11 +1743,18 @@ bool CSelectableCore::Process()
while (Handle)
{
// Auto manage handles
if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent)
if ((Handle->State == csOpenRequest))
{
// Resolve then open socket
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
Open( Handle, false );
}
}
else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) )
{
// Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) {
Open( Handle );
Open( Handle, false );
}
}