Major Update:
- Implement consistent Function addition to application
- Use TYPE_XXX constants to declare function type
- Use NewXXXX() methods to call constructor correctly
- Add FunctionType list (with constructor) to Application
- Create Function by comparison to FunctionType list
- Simplify LoadConfig() and Init() methods for functions
- Combine methods into Init() method
- Pass relevant data member to Init() method
- Remove all CDataMember references on functions
- ApplicationCore:
- Split ReadParam() method from LoadConfig() method
- Split main configuration into separate files:
- config/ - main config file, general application settings
- definition/ - application definition, e.g. function blocks
- Definition and Address List files specified in config file
- Load address file in address/ branch
- Made DataTree & JSONparser private
- Made Config, Definition & Address branches public
- Removed unnecessary branch references
- Improved event logging
- DataTreeCore:
- Allow GetChFirstChild & GetChElement to create parent branches
with correct type, ie. Object/Array
- Remove unnecessary Create param from GetXxx functions
- Bug fix: Print empty objects/arrays correct, ie. empty brackets
- Bug fix: Adding element at specific index
- Bug fix: Error when get/create string value with "null"
- FunctionCore:
- Type param now set as constant via constructor
- Create empty Handles & Channels objects if none in Config
- SelectableCore:
- Add Queue length parameter to handles for UNIX and TCP sockets
- DeviceCore:
- Bug fix: missing Process() method
This commit is contained in:
@@ -34,8 +34,13 @@ extern CApplication * Application;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CSelectableCore::CSelectableCore( const char * pName, const char * pType ) :
|
||||
CFunctionCore( pName, pType )
|
||||
// Function Constructor
|
||||
CFunctionCore * NewSelectableCore( const char * Name ) {
|
||||
return (CFunctionCore*) new CSelectableCore( Name );
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CSelectableCore::CSelectableCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
|
||||
{
|
||||
// Quick access
|
||||
Selector = Application->Selector;
|
||||
@@ -64,53 +69,47 @@ CSelectableCore::~CSelectableCore()
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CSelectableCore::LoadConfigData()
|
||||
bool CSelectableCore::Init( CDataMember * FunctionConfig )
|
||||
{
|
||||
CDataMember * TempMember;
|
||||
CDataMember * HandleConfig;
|
||||
CDataMember * AddressDef;
|
||||
CDataMember * SerialConfig;
|
||||
THandle * Handle;
|
||||
char * Type;
|
||||
char * Name;
|
||||
char Path[100];
|
||||
char * Address;
|
||||
char * Port;
|
||||
char * ParityText;
|
||||
char * FlowCtrlText;
|
||||
short Parity;
|
||||
short FlowCtrl;
|
||||
short Queue;
|
||||
long Delay;
|
||||
|
||||
// Call Previous load config
|
||||
CFunctionCore::LoadConfigData();
|
||||
if (!CFunctionCore::Init( FunctionConfig ))
|
||||
return false;
|
||||
|
||||
// Load Handles
|
||||
if ((TempMember = ConfigMember->GetChild( "Handles", false ))) {
|
||||
TempMember = TempMember->GetFirstChild();
|
||||
}
|
||||
while (TempMember)
|
||||
HandleConfig = FunctionConfig->GetChFirstChild( "Handles", true );
|
||||
while (HandleConfig)
|
||||
{
|
||||
// Check if name is valid
|
||||
if (!TempMember->GetName() || !*TempMember->GetName())
|
||||
continue;
|
||||
|
||||
// Create Handle and channel link
|
||||
Handle = CreateHandle( TempMember->GetName(), false );
|
||||
Handle->Channel = GetChannel( TempMember->GetChStr( "Channel" ) );
|
||||
Handle = CreateHandle( HandleConfig->GetName(), false );
|
||||
Handle->Channel = GetChannel( HandleConfig->GetChStr( "Channel" ) );
|
||||
|
||||
Type = (char*)TempMember->GetChStr( "Type", "TCPclient", true );
|
||||
Type = (char*)HandleConfig->GetChStr( "Type", "TCPclient", true );
|
||||
if (!strcasecmp( Type, "Serial" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Port/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get address list value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Port/Address", NULL, true ); // Get default value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Port/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Port/Address", NULL, true ); // Get default value
|
||||
}
|
||||
SetSerialHandle( Handle, Address );
|
||||
|
||||
// Update configuration if specified
|
||||
if ((SerialConfig = TempMember->GetChild( "Port/SerialConfig", false )))
|
||||
if ((SerialConfig = HandleConfig->GetChild( "Port/SerialConfig", false )))
|
||||
{
|
||||
ParityText = (char*)SerialConfig->GetChStr( "Parity", "none", true );
|
||||
if (!strcasecmp( ParityText, "none" ))
|
||||
@@ -143,117 +142,101 @@ bool CSelectableCore::LoadConfigData()
|
||||
}
|
||||
else if (!strcasecmp( Type, "LinePrinter" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Port/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get address list value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Port/Address", NULL, true ); // Get default value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Port/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Port/Address", NULL, true ); // Get default value
|
||||
}
|
||||
SetLinePrinterHandle( Handle, Address );
|
||||
}
|
||||
else if (!strcasecmp( Type, "UNIXserver" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Socket/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get AddressList Address value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
}
|
||||
SetUnixHandle( Handle, ctUNIXserver, Address );
|
||||
Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true );
|
||||
SetUnixHandle( Handle, ctUNIXserver, Address, Queue );
|
||||
}
|
||||
else if (!strcasecmp( Type, "UNIXclient" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Socket/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get AddressList Address value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
}
|
||||
SetUnixHandle( Handle, ctUNIXclient, Address );
|
||||
SetUnixHandle( Handle, ctUNIXclient, Address, 0 );
|
||||
}
|
||||
else if (!strcasecmp( Type, "UDPserver" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Socket/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get AddressList Address value
|
||||
sprintf( Path, "Address/%s/Port", Name );
|
||||
Port = (char*)DataTree->GetChStr( Path, "0", true ); // Get AddressList Port value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)TempMember->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
Delay = TempMember->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), Delay );
|
||||
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), 0, Delay );
|
||||
}
|
||||
else if (!strcasecmp( Type, "UDPclient" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Socket/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get AddressList Address value
|
||||
sprintf( Path, "Address/%s/Port", Name );
|
||||
Port = (char*)DataTree->GetChStr( Path, "0", true ); // Get AddressList Port value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)TempMember->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
Delay = TempMember->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), Delay );
|
||||
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), 0, Delay );
|
||||
}
|
||||
else if (!strcasecmp( Type, "TCPserver" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Socket/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get AddressList Address value
|
||||
sprintf( Path, "Address/%s/Port", Name );
|
||||
Port = (char*)DataTree->GetChStr( Path, "0", true ); // Get AddressList Port value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)TempMember->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
Delay = TempMember->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Delay );
|
||||
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
Queue = HandleConfig->GetChInt( "Socket/Queue", 2, true );
|
||||
SetSocketHandle( Handle, ctTCPserver, Address, strlcase(Port), Queue, Delay );
|
||||
}
|
||||
else if (!strcasecmp( Type, "TCPclient" ))
|
||||
{
|
||||
if ((Name = (char*)TempMember->GetChStr( "Socket/Name", NULL ))) {
|
||||
sprintf( Path, "Address/%s/Address", Name );
|
||||
Address = (char*)DataTree->GetChStr( Path, NULL, true ); // Get AddressList Address value
|
||||
sprintf( Path, "Address/%s/Port", Name );
|
||||
Port = (char*)DataTree->GetChStr( Path, "0", true ); // Get AddressList Port value
|
||||
if ((Name = (char*)HandleConfig->GetChStr( "Socket/Name", NULL )) && (AddressDef = Application->AddressList->GetChild( Name ))) {
|
||||
Address = (char*)AddressDef->GetChStr( "Address", NULL, true ); // Get address list value
|
||||
Port = (char*)AddressDef->GetChStr( "Port", "0", true ); // Get AddressList Port value
|
||||
} else {
|
||||
Address = (char*)HandleConfig->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)HandleConfig->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
else {
|
||||
Address = (char*)TempMember->GetChStr( "Socket/Address", NULL, true ); // Get default Address value
|
||||
Port = (char*)TempMember->GetChStr( "Socket/Port", "0", true ); // Get default Port value
|
||||
}
|
||||
Delay = TempMember->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), Delay );
|
||||
Delay = HandleConfig->GetChInt( "Socket/ResolveDelay", 0, true );
|
||||
SetSocketHandle( Handle, ctTCPclient, Address, strlcase(Port), 0, Delay );
|
||||
}
|
||||
else if (!strcasecmp( Type, "ForkPipe" )) {
|
||||
Address = (char*)TempMember->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value
|
||||
Address = (char*)HandleConfig->GetChStr( "Fork/ExecPath", NULL, true ); // Get default value
|
||||
SetForkPipeHandle( Handle, Address );
|
||||
}
|
||||
|
||||
// Set Auto Mange
|
||||
SetAutoManage( Handle, TempMember->GetChBool( "AutoManage/Enabled", true, true ),
|
||||
TempMember->GetChBool( "AutoManage/Persistent", false, true ),
|
||||
TempMember->GetChInt( "AutoManage/ReopenDelay", 2000, true ),
|
||||
TempMember->GetChInt( "AutoManage/CloseTimeout", 2000, true ));
|
||||
// Set Auto Manage
|
||||
SetAutoManage( Handle, HandleConfig->GetChBool( "AutoManage/Enabled", true, true ),
|
||||
HandleConfig->GetChBool( "AutoManage/Persistent", false, true ),
|
||||
HandleConfig->GetChInt( "AutoManage/ReopenDelay", 2000, true ),
|
||||
HandleConfig->GetChInt( "AutoManage/CloseTimeout", 2000, true ));
|
||||
|
||||
// Input buffer
|
||||
SetInBuffer( Handle, TempMember->GetChInt( "InputBuffer/Size", 0 ),
|
||||
TempMember->GetChInt( "InputBuffer/Timeout", 250 ),
|
||||
TempMember->GetChStr( "InputBuffer/Marker", "" ),
|
||||
TempMember->GetChInt( "InputBuffer/MarkerLen", 0 ) );
|
||||
SetOutBuffer( Handle, TempMember->GetChInt( "OutputBuffer/Size", 0 ) );
|
||||
SetInBuffer( Handle, HandleConfig->GetChInt( "InputBuffer/Size", 0 ),
|
||||
HandleConfig->GetChInt( "InputBuffer/Timeout", 250 ),
|
||||
HandleConfig->GetChStr( "InputBuffer/Marker", "" ),
|
||||
HandleConfig->GetChInt( "InputBuffer/MarkerLen", 0 ) );
|
||||
SetOutBuffer( Handle, HandleConfig->GetChInt( "OutputBuffer/Size", 0 ) );
|
||||
|
||||
// Next
|
||||
TempMember = TempMember->GetNextPeer();
|
||||
HandleConfig = HandleConfig->GetNextPeer();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -458,7 +441,7 @@ bool CSelectableCore::SetForkPipeHandle( THandle * Handle, const char * ExecPath
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CSelectableCore::SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName )
|
||||
bool CSelectableCore::SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue )
|
||||
{
|
||||
// Validate
|
||||
if (!Handle || !FileName ||
|
||||
@@ -478,6 +461,7 @@ bool CSelectableCore::SetUnixHandle( THandle * Handle, EConnectType Type, const
|
||||
// Set name
|
||||
Handle->Path = (char*)malloc( strlen(FileName)+1 );
|
||||
strcpy( Handle->Path, FileName );
|
||||
Handle->Queue = Queue;
|
||||
|
||||
// Log event
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as %s [%s]",
|
||||
@@ -486,7 +470,7 @@ bool CSelectableCore::SetUnixHandle( THandle * Handle, EConnectType Type, const
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, long ResolveDelay )
|
||||
bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay )
|
||||
{
|
||||
// Validate
|
||||
if (!Handle || !HostName || !PortName ||
|
||||
@@ -517,6 +501,8 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
|
||||
Handle->AddressList = NULL;
|
||||
Handle->AddressInfo = NULL;
|
||||
|
||||
Handle->Queue = Queue;
|
||||
|
||||
// Log event
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as %s [%s:%s]",
|
||||
ProcessName, Name, Handle->Name, ConnectTypeName[Type], HostName, PortName );
|
||||
@@ -897,7 +883,7 @@ THandle * CSelectableCore::OpenUNIXserverSocket( THandle * Handle )
|
||||
};
|
||||
|
||||
// Create que for 5 connections
|
||||
if (listen( Handle->FD, 5 ) < 0)
|
||||
if (listen( Handle->FD, Handle->Queue ) < 0)
|
||||
{
|
||||
// Log Event
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to listen on UNIX Server socket [%s] (%s)",
|
||||
@@ -1060,7 +1046,7 @@ THandle * CSelectableCore::OpenUNIXremoteSocket( THandle * Handle )
|
||||
// Create Remote Client Handle
|
||||
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
|
||||
*RemoteClient = CreateHandle( ClientName, false );
|
||||
if (!SetUnixHandle( *RemoteClient, ctUNIXremote, Handle->Path )) {
|
||||
if (!SetUnixHandle( *RemoteClient, ctUNIXremote, Handle->Path, 0 )) {
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - UNIX Server failed to configure Remote Client connection (%s)",
|
||||
ProcessName, Name, Handle->Name, strerror(errno) );
|
||||
return NULL;
|
||||
@@ -1286,7 +1272,7 @@ THandle * CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientA
|
||||
// Create Remote Client Handle
|
||||
sprintf( ClientName, "%s-%d", Handle->Name, ClientCount );
|
||||
*RemoteClient = CreateHandle( ClientName, false );
|
||||
if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0 )) {
|
||||
if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0, 0 )) {
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - UDP Server failed to configure Remote Client connection (%s)",
|
||||
ProcessName, Name, Handle->Name, strerror(errno) );
|
||||
return NULL;
|
||||
@@ -1442,7 +1428,7 @@ THandle * CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayReso
|
||||
};
|
||||
|
||||
// Create que for 5 connections
|
||||
if (listen( Handle->FD, 5 ) < 0)
|
||||
if (listen( Handle->FD, Handle->Queue ) < 0)
|
||||
{
|
||||
// Log Event
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Failed to listen on TCP Server socket [%s:%s] (%s)",
|
||||
@@ -1524,7 +1510,7 @@ THandle * CSelectableCore::OpenTCPremoteSocket( THandle * Handle )
|
||||
// Create Remote Client Handle
|
||||
sprintf( ClientName, "%s-%d", Handle->Name, ClientFD );
|
||||
*RemoteClient = CreateHandle( ClientName, false );
|
||||
if (!SetSocketHandle( *RemoteClient, ctTCPremote, ClientAddress, ClientPort, 0 )) {
|
||||
if (!SetSocketHandle( *RemoteClient, ctTCPremote, ClientAddress, ClientPort, 0, 0 )) {
|
||||
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - TCP Server failed to configure Remote Client connection (%s)",
|
||||
ProcessName, Name, Handle->Name, strerror(errno) );
|
||||
return NULL;
|
||||
|
||||
Reference in New Issue
Block a user