#include "CPlugInList.h"
#include "CServerPlugin.h"
#include "CLauncher.h"
#include "DSUtils.h"
#include "PrivateTypes.h"
#include "SharedConsts.h"
#include "CPluginConfig.h"
#include "CLog.h"
#include "CNodeList.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <CoreFoundation/CoreFoundation.h>
extern CFRunLoopRef gServerRunLoop;
extern DSMutexSemaphore *gKerberosMutex;
extern CPluginConfig *gPluginConfig;
extern DSMutexSemaphore *gLazyPluginLoadingLock;
extern CPlugInList *gPlugins;
extern CNodeList *gNodeList;
CPlugInList::CPlugInList ( void )
{
fPICount = 0;
fTable = nil;
fTableTail = nil;
}
CPlugInList::~CPlugInList ( void )
{
}
sInt32 CPlugInList::AddPlugIn ( const char *inName,
const char *inVersion,
const char *inConfigAvail,
const char *inConfigFile,
FourCharCode inKey,
CServerPlugin *inPluginPtr,
CFPlugInRef inPluginRef,
CFUUIDRef inCFuuidFactory,
uInt32 inULVers )
{
sInt32 siResult = eDSInvalidPlugInConfigData;
sTableData *aTableEntry = nil;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( eDSNullParameter );
}
aTableEntry = (sTableData *)calloc(1, sizeof(sTableData));
if (fTableTail != nil)
{
fTableTail->pNext = aTableEntry;
fTableTail = aTableEntry;
}
else
{
fTable = aTableEntry;
fTableTail = aTableEntry;
}
fTableTail->pNext = nil;
fTableTail->fName = inName;
fTableTail->fVersion = inVersion;
fTableTail->fConfigAvail = inConfigAvail;
fTableTail->fConfigFile = inConfigFile;
fTableTail->fPluginPtr = inPluginPtr;
if ( inPluginRef )
{
fTableTail->fPluginRef = inPluginRef;
CFRetain( fTableTail->fPluginRef );
}
if ( inCFuuidFactory )
{
fTableTail->fCFuuidFactory = inCFuuidFactory;
CFRetain( fTableTail->fCFuuidFactory );
}
if ( inULVers )
fTableTail->fULVers = inULVers;
fTableTail->fKey = inKey;
ePluginState pluginState = gPluginConfig->GetPluginState( fTableTail->fName );
fTableTail->fState = pluginState | kUninitialized;
fPICount++;
siResult = eDSNoErr;
}
catch( sInt32 err )
{
siResult = err;
}
fMutex.Signal();
return( siResult );
}
void CPlugInList::LoadPlugin( sTableData *inTableEntry )
{
bool done = false;
sInt32 siResult = eDSNoErr;
uInt32 uiCntr = 0;
uInt32 uiAttempts = 100;
uInt32 uiWaitTime = 1;
sHeader aHeader;
ePluginState pluginState = kUnknownState;
CServerPlugin *ourPluginPtr= nil;
gLazyPluginLoadingLock->Wait();
try
{
if ( inTableEntry->fPluginPtr == nil)
{
inTableEntry->fPluginPtr = new CServerPlugin( inTableEntry->fPluginRef, inTableEntry->fCFuuidFactory, inTableEntry->fKey, inTableEntry->fULVers, inTableEntry->fName );
ourPluginPtr = (CServerPlugin *)inTableEntry->fPluginPtr;
if ( ourPluginPtr == NULL ) throw( (sInt32)eMemoryError );
ourPluginPtr->Validate( inTableEntry->fVersion, inTableEntry->fKey );
if ( gPlugins != nil )
{
while ( !done )
{
uiCntr++;
siResult = ourPluginPtr->Initialize();
if ( ( siResult != eDSNoErr ) && ( uiCntr == 1 ) )
{
ERRORLOG3( kLogApplication, "Attempt #%l to initialize plug-in %s failed.\n Will retry initialization at most 100 times every %l second.", uiCntr, ourPluginPtr->GetPluginName(), uiWaitTime );
}
if ( siResult == eDSNoErr )
{
DBGLOG2( kLogApplication, "Initialization of plug-in %s succeeded with #%l attempt.", ourPluginPtr->GetPluginName(), uiCntr );
gPlugins->SetState( ourPluginPtr->GetPluginName(), kInitialized );
if (gServerRunLoop != NULL)
{
aHeader.fType = kServerRunLoop;
aHeader.fResult = eDSNoErr;
aHeader.fContextData = (void *)gServerRunLoop;
siResult = ourPluginPtr->ProcessRequest( (void*)&aHeader ); }
if (gKerberosMutex != NULL)
{
aHeader.fType = kKerberosMutex;
aHeader.fResult = eDSNoErr;
aHeader.fContextData = (void *)gKerberosMutex;
ourPluginPtr->ProcessRequest( (void*)&aHeader ); }
pluginState = gPluginConfig->GetPluginState( ourPluginPtr->GetPluginName() );
if ( pluginState == kInactive )
{
siResult = ourPluginPtr->SetPluginState( kInactive );
if ( siResult == eDSNoErr )
{
SRVRLOG1( kLogApplication, "Plug-in %s state is now inactive.", ourPluginPtr->GetPluginName() );
gPlugins->SetState( ourPluginPtr->GetPluginName(), kInactive );
}
else
{
ERRORLOG2( kLogApplication, "Unable to set %s plug-in state to inactive. Received error %l.", ourPluginPtr->GetPluginName(), siResult );
}
}
else
{
siResult = ourPluginPtr->SetPluginState( kActive );
if ( siResult == eDSNoErr )
{
SRVRLOG1( kLogApplication, "Plug-in %s state is now active.", ourPluginPtr->GetPluginName() );
gPlugins->SetState( ourPluginPtr->GetPluginName(), kActive );
}
else
{
ERRORLOG2( kLogApplication, "Unable to set %s plug-in state to active. Received error %l.", ourPluginPtr->GetPluginName(), siResult );
}
}
done = true;
}
if ( !done )
{
if ( uiCntr == uiAttempts )
{
ERRORLOG2( kLogApplication, "%l attempts to initialize plug-in %s failed.\n Setting plug-in state to inactive.", uiCntr, ourPluginPtr->GetPluginName() );
gPlugins->SetState( ourPluginPtr->GetPluginName(), kInactive | kFailedToInit );
siResult = ourPluginPtr->SetPluginState( kInactive );
done = true;
}
else
{
fWaitToInit.Wait( uiWaitTime * kMilliSecsPerSec );
}
}
}
}
SRVRLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", loaded on demand successfully.", inTableEntry->fName, inTableEntry->fVersion );
}
}
catch( sInt32 err )
{
SRVRLOG3( kLogApplication, "Plugin \"%s\", Version \"%s\", failed to load on demand (%d).", inTableEntry->fName, inTableEntry->fVersion, err );
}
gLazyPluginLoadingLock->Signal();
}
void CPlugInList::InitPlugIns ( void )
{
sTableData *aTableEntry = nil;
fMutex.Wait();
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( (aTableEntry->fName != nil) && (aTableEntry->fPluginPtr != nil) )
{
try
{
CLauncher *cpLaunch = new CLauncher( (CServerPlugin *)aTableEntry->fPluginPtr );
if ( cpLaunch != nil )
{
cpLaunch->StartThread();
}
DBGLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", activated successfully.", aTableEntry->fName, aTableEntry->fVersion );
}
catch( sInt32 err )
{
DBGLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", failed to launch initialization thread.", aTableEntry->fName, aTableEntry->fVersion );
}
}
else if ( aTableEntry->fName != nil )
{
ePluginState pluginState = gPluginConfig->GetPluginState( aTableEntry->fName );
aTableEntry->fState = pluginState | kUninitialized;
DBGLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", referenced to be loaded on demand successfully.", aTableEntry->fName, aTableEntry->fVersion );
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
}
sInt32 CPlugInList::IsPresent ( const char *inName )
{
sInt32 siResult = ePluginNameNotFound;
sTableData *aTableEntry = nil;
fMutex.Wait();
if ( inName == nil )
{
return( eDSNullParameter );
}
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( aTableEntry->fName != nil )
{
if ( ::strcmp( aTableEntry->fName, inName ) == 0 )
{
siResult = eDSNoErr;
break;
}
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( siResult );
}
sInt32 CPlugInList::SetState ( const char *inName, const uInt32 inState )
{
sInt32 siResult = ePluginNameNotFound;
sTableData *aTableEntry = nil;
uInt32 curState = kUnknownState;
fMutex.Wait();
if ( inName == nil )
{
return( eDSNullParameter );
}
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( aTableEntry->fName != nil )
{
if ( ::strcmp( aTableEntry->fName, inName ) == 0 )
{
curState = aTableEntry->fState;
if ( (inState & kActive) && aTableEntry->fPluginPtr == NULL )
{
fMutex.Signal();
gNodeList->Lock();
fMutex.Wait();
LoadPlugin( aTableEntry );
gNodeList->Unlock();
}
aTableEntry->fState = inState;
if ( !( curState & inState ) && ( aTableEntry->fPluginPtr ) )
aTableEntry->fPluginPtr->SetPluginState(inState);
siResult = eDSNoErr;
break;
}
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( siResult );
}
sInt32 CPlugInList::GetState ( const char *inName, uInt32 *outState )
{
sInt32 siResult = ePluginNameNotFound;
sTableData *aTableEntry = nil;
fMutex.Wait();
if ( inName == nil )
{
return( eDSNullParameter );
}
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( aTableEntry->fName != nil )
{
if ( ::strcmp( aTableEntry->fName, inName ) == 0 )
{
*outState = aTableEntry->fState;
siResult = eDSNoErr;
break;
}
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( siResult );
}
uInt32 CPlugInList::GetPlugInCount ( void )
{
return( fPICount );
}
uInt32 CPlugInList::GetActiveCount ( void )
{
uInt32 activeCount = 0;
sTableData *aTableEntry = nil;
fMutex.Wait();
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( aTableEntry->fName == nil )
{
if ( aTableEntry->fState & kActive )
{
activeCount++;
}
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( activeCount );
}
CServerPlugin* CPlugInList::GetPlugInPtr ( const char *inName, bool loadIfNeeded )
{
CServerPlugin *pResult = nil;
sTableData *aTableEntry = nil;
fMutex.Wait();
if ( inName == nil )
{
return( nil );
}
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( (aTableEntry->fName != nil) )
{
if ( ::strcmp( aTableEntry->fName, inName ) == 0 )
{
if ( (aTableEntry->fPluginPtr == NULL) && loadIfNeeded )
{
fMutex.Signal();
gNodeList->Lock();
fMutex.Wait();
LoadPlugin( aTableEntry );
gNodeList->Unlock();
}
pResult = aTableEntry->fPluginPtr;
break;
}
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( pResult );
}
CServerPlugin* CPlugInList::GetPlugInPtr ( const uInt32 inKey, bool loadIfNeeded )
{
CServerPlugin *pResult = nil;
sTableData *aTableEntry = nil;
fMutex.Wait();
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if ( (aTableEntry->fName != nil) )
{
if ( aTableEntry->fKey == inKey )
{
if ( aTableEntry->fPluginPtr == NULL
&& (gPluginConfig->GetPluginState(aTableEntry->fName) & kActive)
&& loadIfNeeded )
{
fMutex.Signal();
gNodeList->Lock();
fMutex.Wait();
LoadPlugin( aTableEntry );
gNodeList->Unlock();
}
pResult = aTableEntry->fPluginPtr;
break;
}
}
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( pResult );
}
CServerPlugin* CPlugInList::Next ( uInt32 *inIndex )
{
CServerPlugin *pResult = nil;
uInt32 tableIndex = 0;
sTableData *aTableEntry = nil;
fMutex.Wait();
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if (tableIndex == *inIndex)
{
if ( (aTableEntry->fName != nil) && (aTableEntry->fPluginPtr != nil) )
{
pResult = aTableEntry->fPluginPtr;
tableIndex++;
break;
}
else
{
*inIndex = tableIndex + 1; }
}
tableIndex++;
aTableEntry = aTableEntry->pNext;
}
*inIndex = tableIndex;
fMutex.Signal();
return( pResult );
}
CPlugInList::sTableData* CPlugInList::GetPlugInInfo ( uInt32 inIndex )
{
uInt32 tableIndex = 0;
sTableData *aTableEntry = nil;
fMutex.Wait();
aTableEntry = fTable;
while ( aTableEntry != nil )
{
if (tableIndex == inIndex)
{
break;
}
tableIndex++;
aTableEntry = aTableEntry->pNext;
}
fMutex.Signal();
return( aTableEntry );
}