From bde14a13da5eb73f2f37d0d403e7d31fbb273d2e Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 9 Jun 2019 22:05:27 +0200 Subject: [PATCH] Major Update: - FunctionCore - Replace Channel->Ready with Channel->State (off/waiting/ready) - Add Function reference to Handle - SelectableBare/Core: - Implement async address resolve with event handling - Create ResolveHandler() signal handler (friend) function - Change Create/Remove/DestroyHandle() methods to virtual methods - Move socket specific code to SelectableCore - Rename ChangeState() to virtual HandleState() - Move ClearHandle() from SelectableBare -> SelectableCore - Implement new/delete from THandle - Set max TCP SYN count on connect --- DeviceCore.cpp | 12 +- FileCore.cpp | 2 +- FunctionCore.cpp | 32 ++--- FunctionCore.h | 14 +- SelectableBare.cpp | 82 +++--------- SelectableCore.cpp | 324 +++++++++++++++++++++++++++++++++++++-------- SelectableCore.h | 42 ++++-- SignalCore.cpp | 18 +-- 8 files changed, 360 insertions(+), 166 deletions(-) diff --git a/DeviceCore.cpp b/DeviceCore.cpp index 902d5d6..d648dae 100644 --- a/DeviceCore.cpp +++ b/DeviceCore.cpp @@ -68,19 +68,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig ) // Add Channels if (!(CmdChannel = GetChannel( "Command" ))) - CmdChannel = AddChannel( "Command", true ); + CmdChannel = AddChannel( "Command", CH_ready ); else - SetChannelState( CmdChannel, true ); + SetChannelState( CmdChannel, CH_ready ); if (!(DeviceChannel = GetChannel( "Device" ))) - DeviceChannel = AddChannel( "Device", true ); + DeviceChannel = AddChannel( "Device", CH_ready ); else - SetChannelState( DeviceChannel, true ); + SetChannelState( DeviceChannel, CH_ready ); if (!(EventChannel = GetChannel( "Event" ))) - EventChannel = AddChannel( "Event", true ); + EventChannel = AddChannel( "Event", CH_ready ); else - SetChannelState( EventChannel, true ); + SetChannelState( EventChannel, CH_ready ); // Load Polling configuration PollConfig = Config->GetChild( "Polling", true ); diff --git a/FileCore.cpp b/FileCore.cpp index 8155e5b..1c0aa95 100644 --- a/FileCore.cpp +++ b/FileCore.cpp @@ -86,7 +86,7 @@ TFileHandle * CFileCore::AddFile( const char * Name, const char * Path, bool Ap // Create Channel if necessary if (CreateChannel) { - AddChannel( Name, false ); + AddChannel( Name, CH_ready ); } // Set Parameters diff --git a/FunctionCore.cpp b/FunctionCore.cpp index c5be8f5..6a3450f 100644 --- a/FunctionCore.cpp +++ b/FunctionCore.cpp @@ -100,7 +100,7 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig ) // Load Channels ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); while (ChannelConfig) { - AddChannel( ChannelConfig->GetName(), false ); + AddChannel( ChannelConfig->GetName(), CH_off ); ChannelConfig = ChannelConfig->GetNextPeer(); } @@ -166,7 +166,7 @@ bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel ) } //--------------------------------------------------------------------------- -TChannel * CFunctionCore::AddChannel( const char * ChannelName, bool Ready ) +TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelState State ) { TChannel ** Channel = NULL; @@ -190,17 +190,17 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, bool Ready ) (*Channel)->Name = strdup( ChannelName ); (*Channel)->Ref = (char*)malloc( strlen(Name)+strlen(ChannelName)+2 ); sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName ); - (*Channel)->Ready = Ready; + (*Channel)->State = State; // Log Event - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', Ready:%s", - ProcessName, Name, ChannelName, (*Channel)->Ref, (((*Channel)->Ready)? "Yes" : "No") ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', State:%s", + ProcessName, Name, ChannelName, (*Channel)->Ref, ChannelStateName[(*Channel)->State] ); } return *Channel; } //--------------------------------------------------------------------------- -bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) +bool CFunctionCore::SetChannelState( TChannel * Channel, const EChannelState State ) { TChannelLink * LinkChannel; @@ -209,14 +209,14 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) return false; // Update state - Channel->Ready = Ready; - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Channel '%s' - Ready:%s", - ProcessName, Name, Channel->Name, ((Ready)? "Yes" : "No") ); + Channel->State = State; + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Channel '%s' - State:%s", + ProcessName, Name, Channel->Name, ChannelStateName[State] ); // Update linked channels LinkChannel = Channel->FirstLink; while (LinkChannel) { - LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, Ready ); + LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, State ); LinkChannel = LinkChannel->Next; } @@ -224,7 +224,7 @@ bool CFunctionCore::SetChannelState( TChannel * Channel, const bool Ready ) } //--------------------------------------------------------------------------- -bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const bool Ready ) +bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState State ) { TChannelLink * LinkChannel; @@ -233,8 +233,8 @@ bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRe if (!(LinkChannel = GetLinkChannel( Channel, SourceRef ))) return false; - if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Link Channel '%s'-->'%s' - Ready:%s", - ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ((Ready)? "Yes" : "No") ); + if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Update Link Channel '%s'-->'%s' - State:%s", + ProcessName, Name, Channel->Name, LinkChannel->Channel->Ref, ChannelStateName[State] ); return true; } @@ -308,9 +308,9 @@ int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, cons ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->Ready) { - if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", - ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); + else if (!Channel->State) { + if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s", + ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->State] ); return 0; } diff --git a/FunctionCore.h b/FunctionCore.h index 4866372..72227e0 100644 --- a/FunctionCore.h +++ b/FunctionCore.h @@ -17,6 +17,12 @@ //--------------------------------------------------------------------------- +// Enumarate Types +typedef enum { CH_off = 0, CH_wait = 1, CH_ready = 2 } EChannelState; +const char ChannelStateName[][15] = { "Off", "Waiting", "Ready" }; + +//--------------------------------------------------------------------------- + // Preview typedef struct SChannel TChannel; typedef struct SChannelLink TChannelLink; @@ -32,7 +38,7 @@ struct SChannel TChannelLink * FirstLink = NULL; // List of channels linked for input/output - bool Ready = false; // Channel ready to receive input + EChannelState State = CH_off; // Channel ready to receive input TChannel * Next = NULL; }; @@ -112,10 +118,10 @@ public: inline const char * GetType() { return Type; }; // Manage Channels - virtual TChannel * AddChannel( const char * ChannelName, const bool Ready ); + virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State ); - virtual bool SetChannelState( TChannel * Channel, const bool Ready ); - virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const bool Ready ); + virtual bool SetChannelState( TChannel * Channel, const EChannelState State ); + virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState State ); // Pushing Data Output -> Input virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 ); diff --git a/SelectableBare.cpp b/SelectableBare.cpp index 48d3f0b..b167ab8 100644 --- a/SelectableBare.cpp +++ b/SelectableBare.cpp @@ -94,7 +94,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh if (!*Handle) { // Create File handle at end of list - *Handle = (THandle*)calloc( 1, sizeof(THandle) ); + *Handle = new THandle; // Set name if (HandleName) { @@ -103,7 +103,8 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh } // Set File Descriptor - (*Handle)->FD = -1; + (*Handle)->Function = this; + (*Handle)->FD = -1; // Log event if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created", @@ -112,7 +113,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh // Create Matching Channel if (CreateChannel) { - (*Handle)->Channel = AddChannel( HandleName, false ); + (*Handle)->Channel = AddChannel( HandleName, CH_off ); } return *Handle; @@ -159,68 +160,16 @@ bool CSelectableBare::DestroyHandle( THandle * Handle ) free( Handle->Name ); if (Handle->Path) free( Handle->Path ); - if (Handle->HostName) - free( Handle->HostName ); - if (Handle->PortName) - free( Handle->PortName ); - if (Handle->AddressInfo) - freeaddrinfo( Handle->AddressList ); - - // 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 ); + delete Handle; return true; } //--------------------------------------------------------------------------- -bool CSelectableBare::ClearHandle( THandle * Handle ) +bool CSelectableBare::HandleState( THandle * Handle, EConnectState State ) { - // Validate - if (!Handle) { - return false; - } - - // Reset Type related parameters - if (Handle->Path) { - free( Handle->Path ); - Handle->Path = 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; - } - - // Reset Parameters - Handle->Type = ctNone; - - // Log event - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", - ProcessName, Name, Handle->Name ); - return true; -} -//--------------------------------------------------------------------------- - -bool CSelectableBare::ChangeState( THandle * Handle, EConnectState State ) -{ - bool Ready; + EChannelState ChannelState = CH_off; // Validate if (!Handle || (Handle->State == State)) @@ -235,9 +184,14 @@ bool CSelectableBare::ChangeState( THandle * Handle, EConnectState State ) // Update Channel if (Handle->Channel) { - Ready = ((Handle->State == csOpen) || (Handle->State == csDataWaiting)); - if (Handle->Channel->Ready != Ready) - SetChannelState( Handle->Channel, Ready ); + if ((Handle->State == csOpenRequest) || (Handle->State == csWaitingtoOpen)) + ChannelState = CH_wait; + else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting)) + ChannelState = CH_ready; + else + ChannelState = CH_off; + if (Handle->Channel->State != ChannelState) + SetChannelState( Handle->Channel, ChannelState ); } return true; } @@ -421,7 +375,7 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve ) SetStartTime( &Handle->LastAction ); // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return (NewHandle)? NewHandle->FD : -1; }; //--------------------------------------------------------------------------- @@ -459,7 +413,7 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen ) ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") ); // Set State - ChangeState( Handle, ((Fail)? csFailed : csClosed) ); + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- @@ -723,7 +677,7 @@ int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, co ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } - else if (!Channel->Ready) { + else if (Channel->State != CH_ready) { // Channel disabled if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not Ready", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); diff --git a/SelectableCore.cpp b/SelectableCore.cpp index 97faf75..0a5110f 100644 --- a/SelectableCore.cpp +++ b/SelectableCore.cpp @@ -40,13 +40,62 @@ CFunctionCore * NewSelectableCore( const char * Name ) { } //--------------------------------------------------------------------------- +// Resolve action handlder +void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ) +{ + TResolveReq * ResolveReq; + THandle * Handle; + + // Validate signal + if ((SignalInfo->si_code != SI_ASYNCNL) || + (SignalInfo->si_signo != SIGRTMIN)) + return; + + // Get Handle & Request + ResolveReq = (TResolveReq*)(SignalInfo->si_value.sival_ptr); + Handle = ResolveReq->Handle; + + ((CSelectableCore*)Handle->Function)->HandleResolve( Handle ); +} +//--------------------------------------------------------------------------- + CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CSelectableBare( pName, pType ) { + // Configure resolve signal handler + ResolveAct.sa_sigaction = &ResolveHandler; + sigemptyset( &ResolveAct.sa_mask ); + ResolveAct.sa_flags = SA_SIGINFO; + + sigaction( SIGRTMIN, &ResolveAct, NULL ); } //--------------------------------------------------------------------------- CSelectableCore::~CSelectableCore() { + THandle * NextHandle = NULL; + bool Result; + + // Destroy File Handles + while (FirstHandle) + { + // Close active resolve request + if (FirstHandle->Resolving && FirstHandle->ResolveReq) { + if ((Result = gai_cancel( FirstHandle->ResolveReq->Request )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)", + ProcessName, Name, FirstHandle->Name, FirstHandle->HostName, FirstHandle->PortName, gai_strerror(Result) ); + DestroyResolveReq( FirstHandle, true ); + HandleState( FirstHandle, csFailed ); + } + } + + // Close handle if open + if ((FirstHandle->State == csOpen) || (FirstHandle->State == csWaitingtoOpen)) + Close( FirstHandle, false ); + + NextHandle = FirstHandle->Next; + DestroyHandle( FirstHandle ); + FirstHandle = NextHandle; + } } //--------------------------------------------------------------------------- @@ -227,6 +276,87 @@ bool CSelectableCore::Init( CDataMember * FunctionConfig ) } //--------------------------------------------------------------------------- +bool CSelectableCore::DestroyHandle( THandle * Handle ) +{ + int Result; + + // Validate Handle + if (!Handle) + return false; + + // Destroy Resolve request + if (Handle->Resolving && Handle->ResolveReq) { + if ((Result = gai_cancel( Handle->ResolveReq->Request )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error canceling Host Name resolve [%s:%s] (%s)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); + } + DestroyResolveReq( Handle, true ); + } + + // Clear parameters + if (Handle->Name) + free( Handle->Name ); + if (Handle->Path) + free( Handle->Path ); + if (Handle->HostName) + free( Handle->HostName ); + if (Handle->PortName) + free( Handle->PortName ); + if (Handle->AddressList) + freeaddrinfo( Handle->AddressList ); + + // 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 + delete Handle; + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::ClearHandle( THandle * Handle ) +{ + // Validate + if (!Handle) { + return false; + } + + // Reset Type related parameters + if (Handle->Path) { + free( Handle->Path ); + Handle->Path = 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; + } + + // Reset Parameters + Handle->Type = ctNone; + + // Log event + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", + ProcessName, Name, Handle->Name ); + return true; +} +//--------------------------------------------------------------------------- + bool CSelectableCore::SetSerialHandle( THandle * Handle, const char * FileName ) { // Validate @@ -427,7 +557,7 @@ THandle * CSelectableCore::OpenSerialPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -470,7 +600,7 @@ THandle * CSelectableCore::OpenLinePrinterPort( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -572,7 +702,7 @@ THandle * CSelectableCore::OpenForkPipe( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -596,7 +726,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -608,7 +738,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -633,7 +763,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -648,7 +778,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -662,7 +792,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle ) } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -688,7 +818,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -715,7 +845,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -734,7 +864,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } } @@ -749,7 +879,7 @@ THandle * CSelectableCore::OpenUNIXclientSocket( THandle * Handle ) } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -846,7 +976,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->Path ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -856,12 +986,17 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle ) bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) { - struct addrinfo hints; - int result; + struct addrinfo * Hints; + TResolveReq * ResolveReq; + sigevent ResolveEvt; + int Result; + + // Ignore if busy resolving + if (Handle->Resolving) + return false; // Check if resolved address available - if (Handle->AddressInfo) - { + if (Handle->AddressInfo) { // Return if address still valid if (!Handle->AddressFailed) return true; @@ -892,47 +1027,117 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) } // Set address specification - memset( &hints, 0, sizeof hints ); + Hints = (struct addrinfo*)calloc( 1, sizeof(struct addrinfo) ); if ((Handle->Type == ctTCPserver) || (Handle->Type == ctTCPclient)) { - hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 - hints.ai_socktype = SOCK_STREAM; + Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 + Hints->ai_socktype = SOCK_STREAM; } else { - hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 - hints.ai_socktype = SOCK_DGRAM; + Hints->ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 + Hints->ai_socktype = SOCK_DGRAM; } + // Create request data + ResolveReq = new TResolveReq; + Handle->ResolveReq = ResolveReq; + + ResolveReq->Handle = Handle; + ResolveReq->Request = (gaicb*)calloc( 1, sizeof(gaicb) ); + + // DNS request / reply structure + ResolveReq->Request->ar_name = Handle->HostName; + ResolveReq->Request->ar_service = Handle->PortName; + ResolveReq->Request->ar_request = Hints; + ResolveReq->Request->ar_result = NULL; + + // Configure signal event + ResolveEvt.sigev_notify = SIGEV_SIGNAL; + ResolveEvt.sigev_signo = SIGRTMIN; + ResolveEvt.sigev_value.sival_ptr = ResolveReq; + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Resolving Host name [%s:%s]...", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); // Should address be resolved later during process() - if (DelayResolve) - { + if (DelayResolve) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Delay resolving of Host Name [%s:%s]", ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); - ChangeState( Handle, csOpenRequest ); + + HandleState( 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/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)", - ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) ); - ChangeState( Handle, csFailed ); + Handle->Resolving = true; + if ((Result = getaddrinfo_a( GAI_NOWAIT, &(Handle->ResolveReq->Request), 1, &ResolveEvt )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); + DestroyResolveReq( Handle, true ); + + HandleState( Handle, csFailed ); + return false; + } + return false; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::DestroyResolveReq( THandle * Handle, bool DestroyResult ) +{ + // Validate + if (!Handle || !Handle->ResolveReq) + return false; + + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Destroying resolve request [%s:%s]", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); + + // Destroy + if (DestroyResult) { + if (Handle->ResolveReq->Request->ar_result) + freeaddrinfo( Handle->ResolveReq->Request->ar_result ); + } + if (Handle->ResolveReq->Request->ar_request) + free( (void*)Handle->ResolveReq->Request->ar_request ); + if (Handle->ResolveReq->Request) + free( Handle->ResolveReq->Request ); + if (Handle->ResolveReq) + delete Handle->ResolveReq; + + // Reset request + Handle->ResolveReq = NULL; + Handle->Resolving = false; + return true; +} +//--------------------------------------------------------------------------- + +bool CSelectableCore::HandleResolve( THandle * Handle ) +{ + bool Result; + + // Validate result + if ((Result = gai_error( Handle->ResolveReq->Request )) != 0) { + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Error resolving Host Name [%s:%s] (%s)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(Result) ); + DestroyResolveReq( Handle, true ); + + HandleState( Handle, csFailed ); return false; } - // Select first address, skip "0.0.0.0" + // Read result + Handle->AddressList = Handle->ResolveReq->Request->ar_result; Handle->AddressInfo = Handle->AddressList; + + // Select first address, skip "0.0.0.0" if (!strcmp( inet_ntoa(((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr), "0.0.0.0" )) Handle->AddressInfo = Handle->AddressInfo->ai_next; + if (!Handle->AddressInfo) { - if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (%s)", - ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, gai_strerror(result) ); + if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to resolve Host Name [%s:%s] (No Result)", + ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName ); freeaddrinfo( Handle->AddressList ); Handle->AddressList = NULL; Handle->AddressInfo = NULL; - ChangeState( Handle, csFailed ); + + HandleState( Handle, csFailed ); return false; } @@ -941,6 +1146,9 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve ) ProcessName, 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) ); + + // Destroy request + DestroyResolveReq( Handle, false ); return true; } //--------------------------------------------------------------------------- @@ -964,7 +1172,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -985,7 +1193,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso Handle->AddressFailed = true; // Change state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -999,7 +1207,7 @@ THandle * CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1081,7 +1289,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set Status - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1098,7 +1306,7 @@ THandle * CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1133,7 +1341,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1146,7 +1354,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -1161,7 +1369,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set state - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } @@ -1181,7 +1389,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1197,7 +1405,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1211,7 +1419,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso } // Set state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } //--------------------------------------------------------------------------- @@ -1313,7 +1521,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) ProcessName, Name, Handle->Name, Handle->HostName ); // Update state - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } } @@ -1324,10 +1532,11 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle ) THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayResolve ) { // Socket options - int KeepAlive_opt = 1; - int TCPidle_opt = 5; - int TCPcnt_opt = 3; - int TCPint_opt = 2; + int KeepAlive_opt = 1; // Enable/disable keep alive + int TCPidle_opt = 5; // Idle time on socket before sending first keep alive signal + int TCPint_opt = 2; // Interval between keep alive signals + int TCPcnt_opt = 3; // No of missed keep alive response before connection fail + int TCPsyn_opt = 3; // Max SYN (connect retries) before open fails // Check state if (Handle->State == csOpen) { @@ -1349,7 +1558,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso ProcessName, Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) ); // Set Status - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; }; @@ -1361,7 +1570,8 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso 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) ) + (setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) || + (setsockopt( Handle->FD, SOL_TCP, TCP_SYNCNT, &TCPsyn_opt, sizeof(TCPsyn_opt)) == -1) ) { // Log Event if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Could not set KeepAlive options [%s:%s] (%s)", @@ -1371,7 +1581,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso close( Handle->FD ); Handle->FD = -1; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } } @@ -1388,7 +1598,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csOpen ); + HandleState( Handle, csOpen ); return Handle; } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EALREADY)) @@ -1403,7 +1613,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso } // Set status - ChangeState( Handle, csWaitingtoOpen ); + HandleState( Handle, csWaitingtoOpen ); return Handle; } else @@ -1422,7 +1632,7 @@ THandle * CSelectableCore::OpenTCPclientSocket( THandle * Handle, bool DelayReso Handle->FD = -1; Handle->AddressFailed = true; - ChangeState( Handle, csFailed ); + HandleState( Handle, csFailed ); return NULL; } } @@ -1614,7 +1824,7 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen ) }; // Change State - ChangeState( Handle, ((Fail)? csFailed : csClosed) ); + HandleState( Handle, ((Fail)? csFailed : csClosed) ); return true; } //--------------------------------------------------------------------------- diff --git a/SelectableCore.h b/SelectableCore.h index 8e7f51c..98490a9 100644 --- a/SelectableCore.h +++ b/SelectableCore.h @@ -10,6 +10,8 @@ // Standard C/C++ Libraries #include +#include +#include // redA Libraries #include "FunctionCore.h" @@ -44,13 +46,14 @@ const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "O // Previews typedef struct SSelectHandle TSelectHandle; typedef struct SHandle THandle; +typedef struct SResolveReq TResolveReq; class CSelect; class CSelectableBare; class CSelectableCore; // Callback function for handle events -typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState State ); +typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState OldState ); //--------------------------------------------------------------------------- @@ -68,7 +71,6 @@ struct SSelectHandle { // List TSelectHandle * Next = NULL; }; - //--------------------------------------------------------------------------- // List or Handles for Selectable Function Object @@ -76,6 +78,7 @@ struct SHandle { // Description char * Name = NULL; EConnectType Type = ctNone; + CSelectableBare * Function = NULL; // State int FD = -1; @@ -103,7 +106,10 @@ struct SHandle { struct addrinfo * AddressInfo = NULL; // Current selected IP Address bool AddressFailed = false; // Indicate failure to connect to address short Queue = 2; // Max waiting connections + long ResolveDelay = 0; // Delay before resolving hostname via DNS + TResolveReq * ResolveReq = NULL; // DNS resolve request + bool Resolving = false; // Busy resolving address // Serial Port config bool SerialConfig = false; @@ -132,6 +138,16 @@ struct SHandle { THandle * Parent = NULL; THandle * Next = NULL; }; +//--------------------------------------------------------------------------- + +struct SResolveReq { + THandle * Handle = NULL; + gaicb * Request = NULL; +}; +//--------------------------------------------------------------------------- + +// Resolving +void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ); //--------------------------------------------------------------------------- @@ -192,9 +208,9 @@ protected: CSelect * Selector = NULL; // Managing File Handles - bool RemoveHandle( THandle * Handle ); - bool DestroyHandle( THandle * Handle ); - bool ChangeState( THandle * Handle, EConnectState State ); + virtual bool RemoveHandle( THandle * Handle ); + virtual bool DestroyHandle( THandle * Handle ); + virtual bool HandleState( THandle * Handle, EConnectState State ); // Get Parameters inline int GetFD( const char * HandleName ) { @@ -241,7 +257,7 @@ public: } // General port parameters - THandle * CreateHandle( const char * HandleName, bool CreateChannel ); + virtual THandle * CreateHandle( const char * HandleName, bool CreateChannel ); virtual CDataMember * GetHandleAddress( THandle * Handle, const char * HandleRef ); bool SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback ); @@ -249,9 +265,6 @@ public: bool SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen ); bool SetOutBuffer( THandle * Handle, int OutBufSize ); - // Specific port parameters - bool ClearHandle( THandle * Handle ); - // FD Operations virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0; virtual bool Close( THandle * Handle, bool QuickReopen ); @@ -291,6 +304,8 @@ public: class CSelectableCore : public CSelectableBare { protected: + struct sigaction ResolveAct; + // Port Operations THandle * OpenSerialPort( THandle * Handle ); bool WriteSerialConfig( THandle * Handle ); @@ -306,6 +321,11 @@ protected: // Socket Operations bool ResolveAddress( THandle * Handle, bool DelayResolve ); + bool HandleResolve( THandle * Handle ); + bool DestroyResolveReq( THandle * Handle, bool DestroyResult ); + + // Managing File Handles + virtual bool DestroyHandle( THandle * Handle ); THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve ); THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort ); @@ -330,6 +350,8 @@ public: virtual bool Init( CDataMember * FunctionConfig ); // Specific port parameters + bool ClearHandle( THandle * Handle ); + bool SetSerialHandle( THandle * Handle, const char * FileName ); bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait ); bool SetLinePrinterHandle( THandle * Handle, const char * FileName ); @@ -346,6 +368,8 @@ public: // Function Interface virtual int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual bool Process(); + + friend void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context ); }; //--------------------------------------------------------------------------- diff --git a/SignalCore.cpp b/SignalCore.cpp index 748304b..7c8654b 100644 --- a/SignalCore.cpp +++ b/SignalCore.cpp @@ -41,21 +41,21 @@ void ConfigureSignalHandlers() sigemptyset( &TermAct.sa_mask ); TermAct.sa_flags = SA_RESTART; - sigaction( SIGHUP, &TermAct, 0 ); - sigaction( SIGINT, &TermAct, 0 ); - sigaction( SIGQUIT, &TermAct, 0 ); - sigaction( SIGTERM, &TermAct, 0 ); - sigaction( SIGTSTP, &TermAct, 0 ); + sigaction( SIGHUP, &TermAct, NULL ); + sigaction( SIGINT, &TermAct, NULL ); + sigaction( SIGQUIT, &TermAct, NULL ); + sigaction( SIGTERM, &TermAct, NULL ); + sigaction( SIGTSTP, &TermAct, NULL ); // Signals for immediate termination AbortAct.sa_handler = SignalAbort; sigemptyset( &AbortAct.sa_mask ); AbortAct.sa_flags = 0; - sigaction( SIGABRT, &AbortAct, 0 ); - sigaction( SIGFPE, &AbortAct, 0 ); - sigaction( SIGILL, &AbortAct, 0 ); - sigaction( SIGSEGV, &AbortAct, 0 ); + sigaction( SIGABRT, &AbortAct, NULL ); + sigaction( SIGFPE, &AbortAct, NULL ); + sigaction( SIGILL, &AbortAct, NULL ); + sigaction( SIGSEGV, &AbortAct, NULL ); } //---------------------------------------------------------------------------