#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
extern CFRunLoopRef gServerRunLoop;
extern CPluginConfig *gPluginConfig;
extern DSMutexSemaphore *gLazyPluginLoadingLock;
extern CPlugInList *gPlugins;
CPlugInList::CPlugInList ( void )
{
fPICount = 0;
::memset( fTable, 0, sizeof( fTable ) );
}
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 = kMaxPlugInsLoaded;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( kInvalidPlugInName );
}
while ( tableIndex < kMaxPlugIns )
{
if ( fTable[ tableIndex ].fName == nil )
{
fTable[ tableIndex ].fName = inName;
fTable[ tableIndex ].fVersion = inVersion;
fTable[ tableIndex ].fConfigAvail = inConfigAvail;
fTable[ tableIndex ].fConfigFile = inConfigFile;
fTable[ tableIndex ].fPluginPtr = inPluginPtr;
if ( inPluginRef )
{
fTable[ tableIndex ].fPluginRef = inPluginRef;
CFRetain( fTable[ tableIndex ].fPluginRef );
}
if ( inCFuuidFactory )
{
fTable[ tableIndex ].fCFuuidFactory = inCFuuidFactory;
CFRetain( fTable[ tableIndex ].fCFuuidFactory );
}
if ( inULVers )
fTable[ tableIndex ].fULVers = inULVers;
fTable[ tableIndex ].fKey = inKey;
ePluginState pluginState = gPluginConfig->GetPluginState( fTable[ tableIndex ].fName );
fTable[ tableIndex ].fState = pluginState | kUninitialized;
fPICount++;
siResult = kPlugInListNoErr;
break;
}
tableIndex++;
}
}
catch( sInt32 err )
{
siResult = err;
}
fMutex.Signal();
return( siResult );
}
sInt32 CPlugInList::DeletePlugIn ( const char *inName )
{
sInt32 siResult = kPlugInNotFound;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( kInvalidPlugInName );
}
while ( tableIndex < kMaxPlugIns )
{
if ( fTable[ tableIndex ].fName != nil )
{
if ( ::strcmp( fTable[ tableIndex ].fName, inName ) == 0 )
{
fTable[ tableIndex ].fName = nil;
fTable[ tableIndex ].fVersion = nil;
fTable[ tableIndex ].fConfigAvail = nil;
fTable[ tableIndex ].fConfigFile = nil;
fTable[ tableIndex ].fPluginPtr = nil;
fTable[ tableIndex ].fKey = 0;
fTable[ tableIndex ].fState = kUnknownState;
if ( fTable[ tableIndex ].fPluginRef )
CFRelease( fTable[ tableIndex ].fPluginRef );
fTable[ tableIndex ].fPluginRef = nil;
if ( fTable[ tableIndex ].fCFuuidFactory )
CFRelease( fTable[ tableIndex ].fCFuuidFactory );
fTable[ tableIndex ].fCFuuidFactory = nil;
fTable[ tableIndex ].fULVers = 0;
fPICount--;
siResult = kPlugInListNoErr;
break;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
siResult = err;
}
fMutex.Signal();
return( siResult );
}
void CPlugInList::LoadPlugin( uInt32 tableIndex )
{
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
{
fTable[ tableIndex ].fPluginPtr = new CServerPlugin( fTable[ tableIndex ].fPluginRef, fTable[ tableIndex ].fCFuuidFactory, fTable[ tableIndex ].fKey, fTable[ tableIndex ].fULVers, fTable[ tableIndex ].fName );
ourPluginPtr = (CServerPlugin *)fTable[ tableIndex ].fPluginPtr;
if ( ourPluginPtr == NULL ) throw( (sInt32)eMemoryError );
ourPluginPtr->Validate( fTable[ tableIndex ].fVersion, fTable[ tableIndex ].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 ); }
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.", fTable[ tableIndex ].fName, fTable[ tableIndex ].fVersion );
}
catch( sInt32 err )
{
SRVRLOG3( kLogApplication, "Plugin \"%s\", Version \"%s\", failed to load on demand (%d).", fTable[ tableIndex ].fName, fTable[ tableIndex ].fVersion, err );
}
gLazyPluginLoadingLock->Signal();
}
void CPlugInList::InitPlugIns ( void )
{
uInt32 tableIndex = 0;
fMutex.Wait();
while ( tableIndex < kMaxPlugIns )
{
if ( (fTable[ tableIndex ].fName != nil) && (fTable[ tableIndex ].fPluginPtr != nil) )
{
try
{
CLauncher *cpLaunch = new CLauncher( (CServerPlugin *)fTable[ tableIndex ].fPluginPtr );
if ( cpLaunch != nil )
{
cpLaunch->StartThread();
}
DBGLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", activated successfully.", fTable[ tableIndex ].fName, fTable[ tableIndex ].fVersion );
}
catch( sInt32 err )
{
DBGLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", failed to launch initialization thread.", fTable[ tableIndex ].fName, fTable[ tableIndex ].fVersion );
}
}
else if ( fTable[ tableIndex ].fName != nil )
{
ePluginState pluginState = gPluginConfig->GetPluginState( fTable[ tableIndex ].fName );
fTable[ tableIndex ].fState = pluginState | kUninitialized;
DBGLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", referenced to be loaded on demand successfully.", fTable[ tableIndex ].fName, fTable[ tableIndex ].fVersion );
}
tableIndex++;
}
fMutex.Signal();
}
sInt32 CPlugInList::IsPresent ( const char *inName )
{
sInt32 siResult = kPlugInNotFound;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( kInvalidPlugInName );
}
while ( tableIndex < kMaxPlugIns )
{
if ( fTable[ tableIndex ].fName != nil )
{
if ( ::strcmp( fTable[ tableIndex ].fName, inName ) == 0 )
{
siResult = kPlugInFound;
break;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
siResult = err;
}
fMutex.Signal();
return( siResult );
}
sInt32 CPlugInList::SetState ( const char *inName, const uInt32 inState )
{
sInt32 siResult = kPlugInNotFound;
uInt32 tableIndex = 0;
uInt32 curState = kUnknownState;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( kInvalidPlugInName );
}
while ( tableIndex < kMaxPlugIns )
{
if ( fTable[ tableIndex ].fName != nil )
{
if ( ::strcmp( fTable[ tableIndex ].fName, inName ) == 0 )
{
curState = fTable[ tableIndex ].fState;
if ( (inState & kActive) && fTable[ tableIndex ].fPluginPtr == NULL )
{
LoadPlugin( tableIndex );
}
fTable[ tableIndex ].fState = inState;
if ( !( curState & inState ) && ( fTable[ tableIndex ].fPluginPtr ) )
fTable[ tableIndex ].fPluginPtr->SetPluginState(inState);
siResult = kPlugInListNoErr;
break;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
siResult = err;
}
fMutex.Signal();
return( siResult );
}
sInt32 CPlugInList::GetState ( const char *inName, uInt32 *outState )
{
sInt32 siResult = kPlugInNotFound;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( kInvalidPlugInName );
}
while ( tableIndex < kMaxPlugIns )
{
if ( fTable[ tableIndex ].fName != nil )
{
if ( ::strcmp( fTable[ tableIndex ].fName, inName ) == 0 )
{
*outState = fTable[ tableIndex ].fState;
siResult = kPlugInListNoErr;
break;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
siResult = err;
}
fMutex.Signal();
return( siResult );
}
uInt32 CPlugInList::GetPlugInCount ( void )
{
return( fPICount );
}
uInt32 CPlugInList::GetActiveCount ( void )
{
uInt32 siResult = 0;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
while ( tableIndex < kMaxPlugIns )
{
if ( fTable[ tableIndex ].fName == nil )
{
if ( fTable[ tableIndex ].fState & kActive )
{
siResult++;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
siResult = 0;
}
fMutex.Signal();
return( siResult );
}
CServerPlugin* CPlugInList::GetPlugInPtr ( const char *inName, bool loadIfNeeded )
{
CServerPlugin *pResult = nil;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
if ( inName == nil )
{
return( nil );
}
while ( tableIndex < kMaxPlugIns )
{
if ( (fTable[ tableIndex ].fName != nil) )
{
if ( ::strcmp( fTable[ tableIndex ].fName, inName ) == 0 )
{
if ( (fTable[ tableIndex ].fPluginPtr == NULL) && loadIfNeeded )
{
LoadPlugin( tableIndex );
}
pResult = fTable[ tableIndex ].fPluginPtr;
break;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
pResult = nil;
}
fMutex.Signal();
return( pResult );
}
CServerPlugin* CPlugInList::GetPlugInPtr ( const uInt32 inKey, bool loadIfNeeded )
{
CServerPlugin *pResult = nil;
uInt32 tableIndex = 0;
fMutex.Wait();
try
{
while ( tableIndex < kMaxPlugIns )
{
if ( (fTable[ tableIndex ].fName != nil) )
{
if ( fTable[ tableIndex ].fKey == inKey )
{
if ( fTable[ tableIndex ].fPluginPtr == NULL
&& (gPluginConfig->GetPluginState(fTable[ tableIndex ].fName) & kActive)
&& loadIfNeeded )
{
LoadPlugin( tableIndex );
}
pResult = fTable[ tableIndex ].fPluginPtr;
break;
}
}
tableIndex++;
}
}
catch( sInt32 err )
{
pResult = nil;
}
fMutex.Signal();
return( pResult );
}
CServerPlugin* CPlugInList::Next ( uInt32 *inIndex )
{
CServerPlugin *pResult = nil;
uInt32 tableIndex = *inIndex;
fMutex.Wait();
try
{
while ( tableIndex < kMaxPlugIns )
{
if ( (fTable[ tableIndex ].fName != nil) && (fTable[ tableIndex ].fPluginPtr != nil) )
{
pResult = fTable[ tableIndex ].fPluginPtr;
tableIndex++;
break;
}
tableIndex++;
}
}
catch( sInt32 err )
{
pResult = nil;
}
*inIndex = tableIndex;
fMutex.Signal();
return( pResult );
}
CPlugInList::sTableData* CPlugInList::GetPlugInInfo ( uInt32 inIndex )
{
sTableData *pResult = nil;
fMutex.Wait();
try
{
if ( inIndex < kMaxPlugIns )
{
pResult = &fTable[ inIndex ];
}
}
catch( sInt32 err )
{
pResult = nil;
}
fMutex.Signal();
return( pResult );
}