#include "CRefTable.h"
#include "CLog.h"
#include "DSNetworkUtilities.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/sysctl.h> // for struct kinfo_proc and sysctl()
#include <syslog.h> // for syslog()
using namespace std;
extern dsBool gLogAPICalls;
extern UInt32 gRefCountWarningLimit;
extern UInt32 gDaemonIPAddress;
extern DSMutexSemaphore *gTableMutex;
extern CRefTable *gRefTable;
CRefTable::CRefTable ( RefDeallocateProc *deallocProc ) : fTableMutex("CRefTable::fTableMutex")
{
fRefCleanUpEntriesHead = nil;
fRefCleanUpEntriesTail = nil;
fClientPIDListLock = new DSMutexSemaphore("CRefTable::fClientPIDListLock");
fTableCount = 0;
::memset( fRefTables, 0, sizeof( fRefTables ) );
fDeallocProc = deallocProc;
}
CRefTable::~CRefTable ( void )
{
UInt32 i = 1;
UInt32 j = 1;
for ( i = 1; i <= kMaxTables; i++ ) {
if ( fRefTables[ i ] != nil )
{
for (j=0; j< kMaxTableItems; j++)
{
if (fRefTables[ i ]->fTableData[j] != nil)
{
free(fRefTables[ i ]->fTableData[j]);
fRefTables[ i ]->fTableData[j] = nil;
}
}
free( fRefTables[ i ] ); fRefTables[ i ] = nil;
}
}
delete(fClientPIDListLock);
fClientPIDListLock = nil;
}
void CRefTable::Lock ( )
{
fTableMutex.WaitLock();
}
void CRefTable::Unlock ( )
{
fTableMutex.SignalLock();
}
tDirStatus CRefTable::VerifyReference ( tDirReference inDirRef,
UInt32 inType,
CServerPlugin **outPlugin,
SInt32 inPID,
UInt32 inIPAddress,
bool inDaemonPID_OK )
{
tDirStatus siResult = eDSNoErr;
sRefEntry *refData = nil;
sPIDInfo *pPIDInfo = nil;
siResult = GetReference( inDirRef, &refData );
if ( siResult == eDSNoErr )
{
if ( refData->fType != inType )
{
DbgLog( kLogHandler, "Given reference value of <%u> found but does not match reference type.", inDirRef);
siResult = eDSInvalidRefType;
}
else
{
siResult = eDSInvalidRefType;
if ( inDaemonPID_OK && inPID == 0 )
{
siResult = eDSNoErr;
}
else if ( (refData->fPID == inPID) && (refData->fIPAddress == inIPAddress) )
{
siResult = eDSNoErr;
}
else
{
pPIDInfo = refData->fChildPID;
while ( (pPIDInfo != nil) && (siResult != eDSNoErr) )
{
if ( (pPIDInfo->fPID == inPID) && (pPIDInfo->fIPAddress == inIPAddress) )
{
siResult = eDSNoErr;
}
pPIDInfo = pPIDInfo->fNext;
}
}
if (siResult == eDSNoErr)
{
if ( outPlugin != nil )
{
*outPlugin = refData->fPlugin;
}
}
}
}
return( siResult );
}
tDirStatus CRefTable::VerifyDirRef ( tDirReference inDirRef,
CServerPlugin **outPlugin,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->VerifyReference( inDirRef, eDirectoryRefType, outPlugin, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::VerifyNodeRef ( tDirNodeReference inDirNodeRef,
CServerPlugin **outPlugin,
SInt32 inPID,
UInt32 inIPAddress)
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->VerifyReference( inDirNodeRef, eNodeRefType, outPlugin, inPID, inIPAddress );
}
return( siResult );
}
char* CRefTable::GetNodeRefName ( tDirNodeReference inDirNodeRef )
{
char* outNodeName = nil;
if ( gRefTable != nil )
{
outNodeName = gRefTable->GetNodeName( inDirNodeRef );
}
return( outNodeName );
}
tDirStatus CRefTable::VerifyRecordRef ( tRecordReference inRecordRef,
CServerPlugin **outPlugin,
SInt32 inPID,
UInt32 inIPAddress,
bool inDaemonPID_OK )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->VerifyReference( inRecordRef, eRecordRefType, outPlugin, inPID, inIPAddress, inDaemonPID_OK );
}
return( siResult );
}
tDirStatus CRefTable::VerifyAttrListRef ( tAttributeListRef inAttributeListRef,
CServerPlugin **outPlugin,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->VerifyReference( inAttributeListRef, eAttrListRefType, outPlugin, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::VerifyAttrValueRef ( tAttributeValueListRef inAttributeValueListRef,
CServerPlugin **outPlugin,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->VerifyReference( inAttributeValueListRef, eAttrValueListRefType, outPlugin, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::NewDirRef ( UInt32 *outNewRef,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->GetNewRef( outNewRef, 0, eDirectoryRefType, nil, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::NewNodeRef ( UInt32 *outNewRef,
CServerPlugin *inPlugin,
UInt32 inParentID,
SInt32 inPID,
UInt32 inIPAddress,
const char *inNodeName)
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->GetNewRef( outNewRef, inParentID, eNodeRefType, inPlugin, inPID, inIPAddress, inNodeName );
}
return( siResult );
}
tDirStatus CRefTable::NewRecordRef ( UInt32 *outNewRef,
CServerPlugin *inPlugin,
UInt32 inParentID,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->GetNewRef( outNewRef, inParentID, eRecordRefType, inPlugin, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::NewAttrListRef ( UInt32 *outNewRef,
CServerPlugin *inPlugin,
UInt32 inParentID,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->GetNewRef( outNewRef, inParentID, eAttrListRefType, inPlugin, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::NewAttrValueRef ( UInt32 *outNewRef,
CServerPlugin *inPlugin,
UInt32 inParentID,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->GetNewRef( outNewRef, inParentID, eAttrValueListRefType, inPlugin, inPID, inIPAddress );
}
return( siResult );
}
tDirStatus CRefTable::RemoveDirRef ( UInt32 inDirRef,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->RemoveRef( inDirRef, eDirectoryRefType, inPID, inIPAddress, true );
}
return( siResult );
}
tDirStatus CRefTable::RemoveNodeRef ( UInt32 inNodeRef,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->RemoveRef( inNodeRef, eNodeRefType, inPID, inIPAddress, true );
}
return( siResult );
}
tDirStatus CRefTable::RemoveRecordRef ( UInt32 inRecRef,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->RemoveRef( inRecRef, eRecordRefType, inPID, inIPAddress, true );
}
return( siResult );
}
tDirStatus CRefTable::RemoveAttrListRef ( UInt32 inAttrListRef,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->RemoveRef( inAttrListRef, eAttrListRefType, inPID, inIPAddress, true );
}
return( siResult );
}
tDirStatus CRefTable::RemoveAttrValueRef ( UInt32 inAttrValueRef,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->RemoveRef( inAttrValueRef, eAttrValueListRefType, inPID, inIPAddress, true );
}
return( siResult );
}
tDirStatus CRefTable::SetNodePluginPtr ( tDirNodeReference inNodeRef,
CServerPlugin *inPlugin )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
if ( gRefTable != nil )
{
siResult = gRefTable->SetPluginPtr( inNodeRef, eNodeRefType, inPlugin );
}
return( siResult );
}
sRefEntry* CRefTable::GetTableRef ( UInt32 inRefNum )
{
UInt32 uiSlot = 0;
UInt32 uiRefNum = (inRefNum & 0x00FFFFFF);
UInt32 uiTableNum = (inRefNum & 0xFF000000) >> 24;
sRefTable *pTable = nil;
sRefEntry *pOutEntry = nil;
fTableMutex.WaitLock();
try
{
pTable = GetThisTable( uiTableNum );
if ( pTable == nil ) throw( (SInt32)eDSInvalidReference );
uiSlot = uiRefNum % kMaxTableItems;
if ( pTable->fTableData != nil)
{
if ( pTable->fTableData[ uiSlot ] != nil )
{
if ( uiRefNum == pTable->fTableData[ uiSlot ]->fRefNum )
{
pOutEntry = pTable->fTableData[ uiSlot ];
}
}
}
}
catch( SInt32 err )
{
DbgLog( kLogAssert, "Reference %l error = %l", inRefNum, err );
}
fTableMutex.SignalLock();
return( pOutEntry );
}
sRefTable* CRefTable::GetNextTable ( sRefTable *inTable )
{
UInt32 uiTblNum = 0;
sRefTable *pOutTable = nil;
fTableMutex.WaitLock();
try
{
if ( inTable == nil )
{
if ( fRefTables[ 1 ] == nil )
{
fRefTables[ 1 ] = (sRefTable *)::calloc( sizeof( sRefTable ), sizeof( char ) );
if ( fRefTables[ 1 ] == nil ) throw((SInt32)eMemoryAllocError);
fRefTables[ 1 ]->fTableNum = 1;
fTableCount = 1;
}
pOutTable = fRefTables[ 1 ];
}
else
{
uiTblNum = inTable->fTableNum + 1;
if (uiTblNum > kMaxTables) throw( (SInt32)eDSInvalidReference );
if ( fRefTables[ uiTblNum ] == nil )
{
fTableCount = uiTblNum;
fRefTables[ uiTblNum ] = (sRefTable *)::calloc( sizeof( sRefTable ), sizeof( char ) );
if ( fRefTables[ uiTblNum ] == nil ) throw((SInt32)eMemoryAllocError);
if (uiTblNum == 0) throw( (SInt32)eDSInvalidReference );
fRefTables[ uiTblNum ]->fTableNum = uiTblNum;
}
pOutTable = fRefTables[ uiTblNum ];
}
}
catch( SInt32 err )
{
DbgLog( kLogAssert, "Reference table error = %l", err );
}
fTableMutex.SignalLock();
return( pOutTable );
}
sRefTable* CRefTable::GetThisTable ( UInt32 inTableNum )
{
sRefTable *pOutTable = nil;
fTableMutex.WaitLock();
pOutTable = fRefTables[ inTableNum ];
fTableMutex.SignalLock();
return( pOutTable );
}
tDirStatus CRefTable::GetNewRef ( UInt32 *outRef,
UInt32 inParentID,
eRefTypes inType,
CServerPlugin *inPlugin,
SInt32 inPID,
UInt32 inIPAddress,
const char *inNodeName)
{
bool done = false;
tDirStatus outResult = eDSNoErr;
sRefTable *pCurTable = nil;
UInt32 uiRefNum = 0;
UInt32 uiCntr = 0;
UInt32 uiSlot = 0;
UInt32 uiTableNum = 0;
UInt32 refCountUpdate = 0;
fTableMutex.WaitLock();
try
{
*outRef = 0;
while ( !done )
{
pCurTable = GetNextTable( pCurTable );
if ( pCurTable == nil ) throw( (SInt32)eDSRefTableAllocError );
if ( pCurTable->fItemCnt < kMaxTableItems )
{
uiCntr = 0;
uiTableNum = pCurTable->fTableNum;
while ( (uiCntr < kMaxTableItems) && !done ) {
if ( (pCurTable->fCurRefNum == 0) ||
(pCurTable->fCurRefNum > 0x000FFFFF) )
{
pCurTable->fCurRefNum = 1;
}
uiRefNum = pCurTable->fCurRefNum++;
uiSlot = uiRefNum % kMaxTableItems;
if ( pCurTable->fTableData[ uiSlot ] == nil )
{
pCurTable->fTableData[ uiSlot ] = (sRefEntry *)::calloc( sizeof( sRefEntry ), sizeof( char ) );
if ( pCurTable->fTableData[ uiSlot ] == nil ) throw( (SInt32)eDSRefTableAllocError );
pCurTable->fTableData[ uiSlot ]->fRefNum = uiRefNum;
pCurTable->fTableData[ uiSlot ]->fType = inType;
pCurTable->fTableData[ uiSlot ]->fParentID = inParentID;
pCurTable->fTableData[ uiSlot ]->fPID = inPID;
pCurTable->fTableData[ uiSlot ]->fIPAddress = inIPAddress;
pCurTable->fTableData[ uiSlot ]->fPlugin = inPlugin;
pCurTable->fTableData[ uiSlot ]->fChildren = nil;
pCurTable->fTableData[ uiSlot ]->fChildPID = nil;
if (inNodeName != nil)
pCurTable->fTableData[ uiSlot ]->fNodeName = strdup(inNodeName);
else
pCurTable->fTableData[ uiSlot ]->fNodeName = nil;
uiTableNum = (uiTableNum << 24);
uiRefNum = uiRefNum | uiTableNum;
*outRef = uiRefNum;
pCurTable->fItemCnt++;
outResult = eDSNoErr;
done = true;
if (inType == eDirectoryRefType)
{
refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, true, uiRefNum);
}
else
{
refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, true);
}
}
uiCntr++; }
}
}
if ( inParentID != 0 )
{
outResult = LinkToParent( *outRef, inType, inParentID, inPID, inIPAddress );
}
}
catch( SInt32 err )
{
outResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( outResult );
}
tDirStatus CRefTable::LinkToParent ( UInt32 inRefNum,
UInt32 inType,
UInt32 inParentID,
SInt32 inPID,
UInt32 inIPAddress )
{
tDirStatus dsResult = eDSNoErr;
sRefEntry *pCurrRef = nil;
sListInfo *pChildInfo = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inParentID );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
pChildInfo = (sListInfo *)::calloc( sizeof( sListInfo ), sizeof( char ) );
if ( pChildInfo == nil ) throw( (SInt32)eDSRefTableAllocError );
pChildInfo->fRefNum = inRefNum;
pChildInfo->fType = inType;
pChildInfo->fPID = inPID;
pChildInfo->fIPAddress = inIPAddress;
pChildInfo->fNext = pCurrRef->fChildren;
pCurrRef->fChildren = pChildInfo;
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CRefTable::UnlinkFromParent ( UInt32 inRefNum )
{
tDirStatus dsResult = eDSNoErr;
UInt32 i = 1;
UInt32 parentID = 0;
sRefEntry *pCurrRef = nil;
sRefEntry *pParentRef = nil;
sListInfo *pCurrChild = nil;
sListInfo *pPrevChild = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inRefNum );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
parentID = pCurrRef->fParentID;
if ( parentID != 0 )
{
pParentRef = GetTableRef( parentID );
if ( pParentRef == nil ) throw( (SInt32)eDSInvalidReference );
pCurrChild = pParentRef->fChildren;
pPrevChild = pParentRef->fChildren;
while ( pCurrChild != nil )
{
if ( pCurrChild->fRefNum == inRefNum )
{
if ( i == 1 )
{
pParentRef->fChildren = pCurrChild->fNext;
}
else
{
pPrevChild->fNext = pCurrChild->fNext;
}
free( pCurrChild );
pCurrChild = nil;
break;
}
pPrevChild = pCurrChild;
pCurrChild = pCurrChild->fNext;
i++;
}
}
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CRefTable::GetReference ( UInt32 inRefNum, sRefEntry **outRefData )
{
tDirStatus dsResult = eDSNoErr;
sRefEntry *pCurrRef = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inRefNum );
if ( pCurrRef == nil )
{
DbgLog( kLogHandler, "Given reference value of <%u> has no valid reference table entry.", inRefNum);
throw( (SInt32)eDSInvalidReference );
}
*outRefData = pCurrRef;
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CRefTable::RemoveRef ( UInt32 inRefNum,
UInt32 inType,
SInt32 inPID,
UInt32 inIPAddress,
bool inbAtTop)
{
tDirStatus dsResult = eDSNoErr;
sRefEntry *pCurrRef = nil;
sRefTable *pTable = nil;
UInt32 uiSlot = 0;
UInt32 uiTableNum = (inRefNum & 0xFF000000) >> 24;
UInt32 uiRefNum = (inRefNum & 0x00FFFFFF);
bool doFree = false;
sPIDInfo *pPIDInfo = nil;
sPIDInfo *pPrevPIDInfo = nil;
UInt32 refCountUpdate = 0;
sRefCleanUpEntry *aRefCleanUpEntries = nil;
sRefCleanUpEntry *aRefCleanUpEntriesIter = nil;
SInt32 deallocResult = eDSNoErr;
fTableMutex.WaitLock();
try
{
dsResult = VerifyReference( inRefNum, inType, nil, inPID, inIPAddress );
if ( dsResult == eDSNoErr )
{
pTable = GetThisTable( uiTableNum );
if ( pTable == nil ) throw( (SInt32)eDSInvalidReference );
uiSlot = uiRefNum % kMaxTableItems;
if ( inType != eDirectoryRefType ) {
dsResult = UnlinkFromParent( inRefNum );
if ( dsResult != eDSNoErr ) throw( (SInt32)dsResult );
}
pCurrRef = GetTableRef( inRefNum ); if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
if (inType != pCurrRef->fType) throw( (SInt32)eDSInvalidReference );
DSFreeString(pCurrRef->fNodeName);
if ( pCurrRef->fChildren != nil )
{
RemoveChildren( pCurrRef->fChildren, inPID, inIPAddress );
}
if ( (pCurrRef->fPID == inPID) && (pCurrRef->fIPAddress == inIPAddress) )
{
pCurrRef->fPID = -1;
if (pCurrRef->fChildPID == nil)
{
doFree = true;
}
}
else
{
pPIDInfo = pCurrRef->fChildPID;
pPrevPIDInfo = pCurrRef->fChildPID;
while (pPIDInfo != nil)
{
if ( (pPIDInfo->fPID == inPID) && (pPIDInfo->fIPAddress == inIPAddress) )
{
if (pPIDInfo == pCurrRef->fChildPID)
{
pCurrRef->fChildPID = pCurrRef->fChildPID->fNext;
free(pPIDInfo);
pPIDInfo = pCurrRef->fChildPID;
pPrevPIDInfo = pCurrRef->fChildPID;
}
else
{
pPrevPIDInfo->fNext = pPIDInfo->fNext;
free(pPIDInfo);
pPIDInfo = pPrevPIDInfo->fNext;
}
}
else
{
pPrevPIDInfo = pPIDInfo;
pPIDInfo = pPIDInfo->fNext;
}
}
if ( (pCurrRef->fPID == -1) && (pCurrRef->fChildPID == nil) )
{
doFree = true;
}
}
if (doFree)
{
if ( pTable->fTableData[ uiSlot ] != nil )
{
if ( uiRefNum == pTable->fTableData[ uiSlot ]->fRefNum )
{
pCurrRef = pTable->fTableData[ uiSlot ];
pTable->fTableData[ uiSlot ] = nil;
pTable->fItemCnt--;
if (inType == eDirectoryRefType)
{
refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, false, inRefNum);
}
else
{
refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, false);
}
if (fDeallocProc != nil)
{
if (fRefCleanUpEntriesHead == nil)
{
fRefCleanUpEntriesHead = (sRefCleanUpEntry *)calloc(1, sizeof(sRefCleanUpEntry));
fRefCleanUpEntriesHead->fRefNum = inRefNum; fRefCleanUpEntriesHead->fType = pCurrRef->fType;
fRefCleanUpEntriesHead->fPlugin = pCurrRef->fPlugin;
fRefCleanUpEntriesHead->fNext = nil;
fRefCleanUpEntriesTail = fRefCleanUpEntriesHead;
}
else
{
fRefCleanUpEntriesTail->fNext = (sRefCleanUpEntry *)calloc(1, sizeof(sRefCleanUpEntry));
fRefCleanUpEntriesTail->fNext->fRefNum = inRefNum; fRefCleanUpEntriesTail->fNext->fType = pCurrRef->fType;
fRefCleanUpEntriesTail->fNext->fPlugin = pCurrRef->fPlugin;
fRefCleanUpEntriesTail->fNext->fNext = nil;
fRefCleanUpEntriesTail = fRefCleanUpEntriesTail->fNext;
}
}
free(pCurrRef);
pCurrRef = nil;
}
}
}
}
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
if (inbAtTop) {
aRefCleanUpEntriesIter = fRefCleanUpEntriesHead;
fRefCleanUpEntriesHead = nil;
fRefCleanUpEntriesTail = nil;
}
fTableMutex.SignalLock();
if (inbAtTop) {
while (aRefCleanUpEntriesIter != nil)
{
aRefCleanUpEntries = aRefCleanUpEntriesIter;
if (aRefCleanUpEntries->fPlugin != nil)
{
deallocResult = (tDirStatus)(*fDeallocProc)( aRefCleanUpEntries->fRefNum, aRefCleanUpEntries->fType, aRefCleanUpEntries->fPlugin );
}
aRefCleanUpEntriesIter = aRefCleanUpEntries->fNext;
free(aRefCleanUpEntries);
}
}
return( dsResult );
}
void CRefTable::RemoveChildren ( sListInfo *inChildList,
SInt32 inPID,
UInt32 inIPAddress )
{
sListInfo *pCurrChild = nil;
sListInfo *pNextChild = nil;
fTableMutex.WaitLock();
try
{
pCurrChild = inChildList;
while ( pCurrChild != nil )
{
pNextChild = pCurrChild->fNext;
if ( ( pCurrChild->fPID == inPID ) && ( pCurrChild->fIPAddress == inIPAddress ) )
{
RemoveRef( pCurrChild->fRefNum, pCurrChild->fType, inPID, inIPAddress, false );
}
pCurrChild = pNextChild;
}
}
catch( SInt32 err )
{
}
fTableMutex.SignalLock();
}
tDirStatus CRefTable::SetPluginPtr ( UInt32 inRefNum, UInt32 inType, CServerPlugin *inPlugin )
{
tDirStatus dsResult = eDSNoErr;
sRefEntry *pCurrRef = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inRefNum );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
if (inType != pCurrRef->fType) throw( (SInt32)eDSInvalidReference );
pCurrRef->fPlugin = inPlugin;
}
catch( SInt32 err )
{
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CRefTable:: AddChildPIDToRef ( UInt32 inRefNum, UInt32 inParentPID, SInt32 inChildPID, UInt32 inIPAddress )
{
tDirStatus dsResult = eDSNoErr;
sRefEntry *pCurrRef = nil;
sPIDInfo *pChildPIDInfo = nil;
gRefTable->Lock();
try
{
dsResult = gRefTable->VerifyReference( inRefNum, eNodeRefType, nil, inParentPID, inIPAddress );
if ( dsResult != eDSNoErr ) throw( (SInt32)dsResult );
pCurrRef = gRefTable->GetTableRef( inRefNum );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
pChildPIDInfo = (sPIDInfo *)::calloc( 1, sizeof( sPIDInfo ) );
if ( pChildPIDInfo == nil ) throw( (SInt32)eDSRefTableAllocError );
pChildPIDInfo->fPID = inChildPID;
pChildPIDInfo->fIPAddress = inIPAddress;
pChildPIDInfo->fNext = pCurrRef->fChildPID;
pCurrRef->fChildPID = pChildPIDInfo;
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
gRefTable->Unlock();
return( dsResult );
}
UInt32 CRefTable:: UpdateClientPIDRefCount ( SInt32 inClientPID, UInt32 inIPAddress, bool inUpRefCount, UInt32 inDirRef )
{
UInt32 aCount = 0;
fClientPIDListLock->WaitLock();
try
{
if ( inDirRef != 0 )
{
tIPPIDDirRefMap::iterator aIPentry = fClientDirRefMap.find( inIPAddress );
if( aIPentry != fClientDirRefMap.end() )
{
tPIDDirRefMap::iterator aPIDentry = aIPentry->second.find( inClientPID );
if( aPIDentry != aIPentry->second.end() )
{
if( inUpRefCount )
{
aPIDentry->second.insert( inDirRef ); }
else
{
aPIDentry->second.erase( inDirRef ); }
}
else {
tDirRefSet newSet;
newSet.insert( inDirRef ); aIPentry->second[inClientPID] = newSet; }
}
else {
tDirRefSet newSet;
tPIDDirRefMap aPIDentry;
newSet.insert( inDirRef ); aPIDentry[inClientPID] = newSet; fClientDirRefMap[inIPAddress] = aPIDentry; }
}
tIPPIDRefCountMap::iterator aIPrefentry = fClientRefCountMap.find( inIPAddress );
if( aIPrefentry != fClientRefCountMap.end() )
{
tPIDRefCountMap::iterator aPIDentry = aIPrefentry->second.find( inClientPID );
if( aPIDentry != aIPrefentry->second.end() )
{
if (inUpRefCount)
{
aPIDentry->second += 1;
aCount = aPIDentry->second;
if ( (aCount > gRefCountWarningLimit) && !(aCount % 25) )
{
syslog(LOG_ALERT,"Potential VM growth in DirectoryService since client PID: %d, has %d open references when the warning limit is %d.", inClientPID, aCount, gRefCountWarningLimit);
DbgLog( kLogHandler, "Potential VM growth in DirectoryService since client PID: %d, has %d open references when the warning limit is %d.", inClientPID, aCount, gRefCountWarningLimit);
}
else if (gLogAPICalls)
{
syslog(LOG_ALERT,"Client PID: %d, has %d open references.", inClientPID, aCount);
}
}
else
{
aPIDentry->second -= 1;
aCount = aPIDentry->second;
if (gLogAPICalls)
{
syslog(LOG_ALERT,"Client PID: %d, has %d open references.", inClientPID, aCount);
}
}
if( aCount == 0 )
{
tIPPIDDirRefMap::iterator aIPentry = fClientDirRefMap.find( inIPAddress );
if( aIPentry != fClientDirRefMap.end() )
{
aIPentry->second.erase( inClientPID );
}
aIPrefentry->second.erase( aPIDentry );
}
}
else {
aIPrefentry->second[ inClientPID ] = 1;
aCount = 1;
}
}
else if( inUpRefCount ) {
tPIDRefCountMap newMap;
newMap[inClientPID] = 1;
fClientRefCountMap[ inIPAddress ] = newMap;
aCount = 1;
}
}
catch( ... )
{
}
fClientPIDListLock->SignalLock();
return aCount;
}
void CRefTable::CleanClientRefs ( UInt32 inIPAddress, UInt32 inPIDorPort )
{
if (gRefTable != nil)
{
gRefTable->DoCleanClientRefs(inIPAddress, inPIDorPort);
}
}
void CRefTable::DoCleanClientRefs ( UInt32 inIPAddress, UInt32 inPIDorPort )
{
tDirRefSet cleanupSet;
fClientPIDListLock->WaitLock();
try
{
tIPPIDDirRefMap::iterator aIPentry = fClientDirRefMap.find( inIPAddress );
if( aIPentry != fClientDirRefMap.end() )
{
tPIDDirRefMap::iterator aPIDentry = aIPentry->second.find( inPIDorPort );
if( aPIDentry != aIPentry->second.end() )
{
cleanupSet = aPIDentry->second;
}
}
tIPPIDRefCountMap::iterator aIPrefentry = fClientRefCountMap.find( inIPAddress );
if( aIPrefentry != fClientRefCountMap.end() )
{
tPIDRefCountMap::iterator aPIDentry = aIPrefentry->second.find( inPIDorPort );
if( aPIDentry != aIPrefentry->second.end() )
{
if (gLogAPICalls)
{
syslog(LOG_ALERT,"Client PID: %d, had %d open references before cleanup.",inPIDorPort, aPIDentry->second);
}
DbgLog( kLogHandler, "Client PID: %d, had %d open references before cleanup.", inPIDorPort, aPIDentry->second );
}
}
if (gLogAPICalls)
{
aIPrefentry = fClientRefCountMap.begin();
while( aIPrefentry != fClientRefCountMap.end() )
{
tPIDRefCountMap::iterator aPIDentry = aIPrefentry->second.begin();
while( aPIDentry != aIPrefentry->second.end() )
{
if( aPIDentry->first != inPIDorPort )
{
syslog( LOG_ALERT, "Client PID: %d, has %d open references in table.", aPIDentry->first, aPIDentry->second );
}
++aPIDentry;
}
++aIPrefentry;
}
}
}
catch( ... )
{
}
fClientPIDListLock->SignalLock();
try
{
tDirRefSet::iterator aIterator = cleanupSet.begin();
while( aIterator != cleanupSet.end() )
{
CRefTable::RemoveDirRef( *aIterator, inPIDorPort, inIPAddress );
++aIterator;
}
}
catch( ... )
{
}
}
void CRefTable::LockClientPIDList( void )
{
fClientPIDListLock->WaitLock();
}
void CRefTable::UnlockClientPIDList( void )
{
fClientPIDListLock->SignalLock();
}
char* CRefTable::CreateNextClientPIDListString( bool inStart, tIPPIDDirRefMap::iterator &inOutIPEntry, tPIDDirRefMap::iterator &inOutPIDEntry )
{
SInt32 theIPAddress = 0;
UInt32 thePIDValue = 0;
UInt32 numDirRefs = 0;
UInt32 theTotalRefCount = 0;
char *outString = nil;
if (!inStart)
{
++inOutPIDEntry;
}
if (inStart)
{
inOutIPEntry = fClientDirRefMap.begin();
}
else if (inOutPIDEntry == inOutIPEntry->second.end())
{
++inOutIPEntry;
if (inOutIPEntry != fClientDirRefMap.end())
{
inOutPIDEntry = inOutIPEntry->second.begin();
}
else
{
return(nil);
}
}
if (inStart)
{
inOutPIDEntry = inOutIPEntry->second.begin();
}
theIPAddress = inOutIPEntry->first;
thePIDValue = inOutPIDEntry->first;
numDirRefs = inOutPIDEntry->second.size();
outString = (char *)calloc(3+15+5+6+5+6+22+numDirRefs*(1+8)+1,sizeof(char*));
DSNetworkUtilities::Initialize();
if (theIPAddress == 0)
{
const char* ipAddressString = DSNetworkUtilities::GetOurIPAddressString(0); if (ipAddressString != nil)
{
sprintf(outString,"IP:%15s",ipAddressString);
}
else
{
sprintf(outString,"IP:%15s","localhost");
}
}
else
{
IPAddrStr ipAddrString;
DSNetworkUtilities::IPAddrToString( theIPAddress, ipAddrString, MAXIPADDRSTRLEN );
if (ipAddrString[0] != '\0')
{
sprintf(outString,"IP:%15s",ipAddrString);
}
else
{
sprintf(outString,"IP:%15s","unknown");
}
}
if (thePIDValue == 0)
{
sprintf(outString+18,",PID:%6u",(unsigned int)::getpid());
}
else
{
sprintf(outString+18,",PID:%6u",(unsigned int)thePIDValue);
}
tIPPIDRefCountMap::iterator aRefCountEntry = fClientRefCountMap.find( inOutIPEntry->first );
if( aRefCountEntry != fClientRefCountMap.end() )
{
tPIDRefCountMap::iterator aPIDEntry = aRefCountEntry->second.find( inOutPIDEntry->first );
if( aPIDEntry != aRefCountEntry->second.end() )
{
theTotalRefCount = aPIDEntry->second;
}
}
sprintf(outString+29,",TotalRefCnt:%6u,DirRefs:",(unsigned int)theTotalRefCount);
tDirRefSet::iterator aDirRefEntry = inOutPIDEntry->second.begin();
UInt32 cntDRs = 0;
while( aDirRefEntry != inOutPIDEntry->second.end() )
{
char* ptr = outString+(57+cntDRs*(1+8));
sprintf(ptr,",%8u",(unsigned int)(*aDirRefEntry));
cntDRs++;
++aDirRefEntry;
}
return(outString);
}
char* CRefTable::CreateNextClientPIDListRecordName( bool inStart,
tIPPIDDirRefMap::iterator &inOutIPEntry, tPIDDirRefMap::iterator &inOutPIDEntry,
char** outIPAddress, char** outPIDValue,
SInt32 &outIP, UInt32 &outPID,
UInt32 &outTotalRefCount,
UInt32 &outDirRefCount, char** &outDirRefs )
{
SInt32 theIPAddress = 0;
UInt32 thePID = 0;
UInt32 numDirRefs = 0;
char *outString = nil;
if (!inStart)
{
++inOutPIDEntry;
}
if (inStart)
{
inOutIPEntry = fClientDirRefMap.begin();
}
else if (inOutPIDEntry == inOutIPEntry->second.end())
{
++inOutIPEntry;
if (inOutIPEntry != fClientDirRefMap.end())
{
inOutPIDEntry = inOutIPEntry->second.begin();
}
else
{
return(nil);
}
}
if (inStart)
{
inOutPIDEntry = inOutIPEntry->second.begin();
}
theIPAddress = inOutIPEntry->first;
outIP = theIPAddress;
thePID = inOutPIDEntry->first;
outPID = thePID;
numDirRefs = inOutPIDEntry->second.size();
outDirRefCount = numDirRefs;
outString = (char *)calloc(15+6+1,sizeof(char*));
DSNetworkUtilities::Initialize();
if (theIPAddress == 0)
{
sprintf(outString,"%s","localhost");
}
else
{
IPAddrStr ipAddrString;
DSNetworkUtilities::IPAddrToString( theIPAddress, ipAddrString, MAXIPADDRSTRLEN );
if (ipAddrString[0] != '\0')
{
sprintf(outString,"%15s",ipAddrString);
}
else
{
sprintf(outString,"%15s","unknown");
}
}
*outIPAddress = strdup(outString);
*outPIDValue = (char*)calloc(6+1, sizeof(char*));
if (thePID == 0)
{
sprintf(outString+strlen(outString),",%u",(unsigned int)::getpid());
sprintf(*outPIDValue, "%u", (unsigned int)::getpid());
}
else
{
sprintf(outString+strlen(outString),",%u",(unsigned int)thePID);
sprintf(*outPIDValue, "%u", (unsigned int)thePID);
}
tIPPIDRefCountMap::iterator aRefCountEntry = fClientRefCountMap.find( inOutIPEntry->first );
if( aRefCountEntry != fClientRefCountMap.end() )
{
tPIDRefCountMap::iterator aPIDEntry = aRefCountEntry->second.find( inOutPIDEntry->first );
if( aPIDEntry != aRefCountEntry->second.end() )
{
outTotalRefCount = aPIDEntry->second;
}
}
tDirRefSet::iterator aDirRefEntry = inOutPIDEntry->second.begin();
outDirRefs = (char **)calloc(numDirRefs + 1, sizeof (char*));
UInt32 idx = 0;
while( aDirRefEntry != inOutPIDEntry->second.end() )
{
char *ptr = (char*)calloc(9, 1 );
outDirRefs[idx] = ptr;
idx++;
sprintf(ptr,"%8u",(unsigned int)(*aDirRefEntry));
++aDirRefEntry;
}
return(outString);
}
void CRefTable::RetrieveRefDataPerClientPIDAndIP( SInt32 inIP, UInt32 inPID, char** inDirRefs,
UInt32 &outNodeRefCount, char** &outNodeRefs,
UInt32 &outRecRefCount, char** &outRecRefs,
UInt32 &outAttrListRefCount, char** &outAttrListRefs,
UInt32 &outAttrListValueRefCount, char** &outAttrListValueRefs )
{
UInt32 nodeRefListSize = 8;
UInt32 recRefListSize = 8;
UInt32 attrListRefListSize = 8;
UInt32 attrListValueRefListSize = 8;
UInt32 aRefNum = 0;
UInt32 uiTableNum = 0;
sRefTable* pTable = nil;
sRefEntry* pCurrRef = nil;
sListInfo* aChildPtr = nil;
char* aRefString = nil;
outNodeRefCount = 0;
outRecRefCount = 0;
outAttrListRefCount = 0;
outAttrListValueRefCount = 0;
outNodeRefs = (char **)calloc(nodeRefListSize + 1, sizeof(char *));
outRecRefs = (char **)calloc(recRefListSize + 1, sizeof(char *));
outAttrListRefs = (char **)calloc(attrListRefListSize + 1, sizeof(char *));
outAttrListValueRefs = (char **)calloc(attrListValueRefListSize + 1, sizeof(char *));
fTableMutex.WaitLock();
if (inDirRefs != nil)
{
UInt32 dirRefIndex = 0;
char *aDirRefString = inDirRefs[dirRefIndex];
while(aDirRefString != nil)
{
aRefNum = atoi(aDirRefString);
SInt32 dsResult = VerifyReference( aRefNum, eDirectoryRefType, nil, inPID, inIP );
if ( dsResult == eDSNoErr )
{
uiTableNum = (aRefNum & 0xFF000000) >> 24;
pTable = GetThisTable( uiTableNum );
if ( pTable != nil )
{
pCurrRef = GetTableRef( aRefNum );
if ( ( pCurrRef != nil ) && (eDirectoryRefType == pCurrRef->fType) )
{
aChildPtr = pCurrRef->fChildren;
while (aChildPtr != nil)
{
aRefString = (char *)calloc(9, 1);
sprintf(aRefString,"%8u",(unsigned int)(aChildPtr->fRefNum));
if ( aChildPtr->fType == eNodeRefType )
{
outNodeRefs[outNodeRefCount] = aRefString;
outNodeRefCount++;
if (outNodeRefCount >= nodeRefListSize)
{
GrowList(outNodeRefs, nodeRefListSize);
}
}
else if ( aChildPtr->fType == eRecordRefType )
{
outRecRefs[outRecRefCount] = aRefString;
outRecRefCount++;
if (outRecRefCount >= recRefListSize)
{
GrowList(outRecRefs, recRefListSize);
}
}
else if ( aChildPtr->fType == eAttrListRefType )
{
outAttrListRefs[outAttrListRefCount] = aRefString;
outAttrListRefCount++;
if (outAttrListRefCount >= attrListRefListSize)
{
GrowList(outAttrListRefs, attrListRefListSize);
}
}
else if ( aChildPtr->fType == eAttrValueListRefType )
{
outAttrListValueRefs[outAttrListValueRefCount] = aRefString;
outAttrListValueRefCount++;
if (outAttrListValueRefCount >= attrListValueRefListSize)
{
GrowList(outAttrListValueRefs, attrListValueRefListSize);
}
}
aChildPtr = aChildPtr->fNext;
}
} } } dirRefIndex++;
aDirRefString = inDirRefs[dirRefIndex];
}
}
if (outNodeRefs != nil)
{
UInt32 nodeRefIndex = 0;
char *aNodeRefString = outNodeRefs[nodeRefIndex];
while(aNodeRefString != nil)
{
aRefNum = atoi(aNodeRefString);
SInt32 dsResult = VerifyReference( aRefNum, eNodeRefType, nil, inPID, inIP );
if ( dsResult == eDSNoErr )
{
uiTableNum = (aRefNum & 0xFF000000) >> 24;
pTable = GetThisTable( uiTableNum );
if ( pTable != nil )
{
pCurrRef = GetTableRef( aRefNum );
if ( ( pCurrRef != nil ) && (eNodeRefType == pCurrRef->fType) )
{
aChildPtr = pCurrRef->fChildren;
while (aChildPtr != nil)
{
aRefString = (char *)calloc(9, 1);
sprintf(aRefString,"%8u",(unsigned int)(aChildPtr->fRefNum));
if ( aChildPtr->fType == eRecordRefType )
{
outRecRefs[outRecRefCount] = aRefString;
outRecRefCount++;
if (outRecRefCount >= recRefListSize)
{
GrowList(outRecRefs, recRefListSize);
}
}
else if ( aChildPtr->fType == eAttrListRefType )
{
outAttrListRefs[outAttrListRefCount] = aRefString;
outAttrListRefCount++;
if (outAttrListRefCount >= attrListRefListSize)
{
GrowList(outAttrListRefs, attrListRefListSize);
}
}
else if ( aChildPtr->fType == eAttrValueListRefType )
{
outAttrListValueRefs[outAttrListValueRefCount] = aRefString;
outAttrListValueRefCount++;
if (outAttrListValueRefCount >= attrListValueRefListSize)
{
GrowList(outAttrListValueRefs, attrListValueRefListSize);
}
}
aChildPtr = aChildPtr->fNext;
}
} } } nodeRefIndex++;
aNodeRefString = outNodeRefs[nodeRefIndex];
}
}
if (outRecRefs != nil)
{
UInt32 recRefIndex = 0;
char *aRecRefString = outRecRefs[recRefIndex];
while(aRecRefString != nil)
{
aRefNum = atoi(aRecRefString);
SInt32 dsResult = VerifyReference( aRefNum, eRecordRefType, nil, inPID, inIP );
if ( dsResult == eDSNoErr )
{
uiTableNum = (aRefNum & 0xFF000000) >> 24;
pTable = GetThisTable( uiTableNum );
if ( pTable != nil )
{
pCurrRef = GetTableRef( aRefNum );
if ( ( pCurrRef != nil ) && (eRecordRefType == pCurrRef->fType) )
{
aChildPtr = pCurrRef->fChildren;
while (aChildPtr != nil)
{
aRefString = (char *)calloc(9, 1);
sprintf(aRefString,"%8u",(unsigned int)(aChildPtr->fRefNum));
if ( aChildPtr->fType == eAttrListRefType )
{
outAttrListRefs[outAttrListRefCount] = aRefString;
outAttrListRefCount++;
if (outAttrListRefCount >= attrListRefListSize)
{
GrowList(outAttrListRefs, attrListRefListSize);
}
}
else if ( aChildPtr->fType == eAttrValueListRefType )
{
outAttrListValueRefs[outAttrListValueRefCount] = aRefString;
outAttrListValueRefCount++;
if (outAttrListValueRefCount >= attrListValueRefListSize)
{
GrowList(outAttrListValueRefs, attrListValueRefListSize);
}
}
aChildPtr = aChildPtr->fNext;
}
} } } recRefIndex++;
aRecRefString = outRecRefs[recRefIndex];
}
}
if (outAttrListRefs != nil)
{
UInt32 attrListRefIndex = 0;
char *aAttrListRefString = outAttrListRefs[attrListRefIndex];
while(aAttrListRefString != nil)
{
aRefNum = atoi(aAttrListRefString);
SInt32 dsResult = VerifyReference( aRefNum, eAttrListRefType, nil, inPID, inIP );
if ( dsResult == eDSNoErr )
{
uiTableNum = (aRefNum & 0xFF000000) >> 24;
pTable = GetThisTable( uiTableNum );
if ( pTable != nil )
{
pCurrRef = GetTableRef( aRefNum );
if ( ( pCurrRef != nil ) && (eAttrListRefType == pCurrRef->fType) )
{
aChildPtr = pCurrRef->fChildren;
while (aChildPtr != nil)
{
aRefString = (char *)calloc(9, 1);
sprintf(aRefString,"%8u",(unsigned int)(aChildPtr->fRefNum));
if ( aChildPtr->fType == eAttrValueListRefType )
{
outAttrListValueRefs[outAttrListValueRefCount] = aRefString;
outAttrListValueRefCount++;
if (outAttrListValueRefCount >= attrListValueRefListSize)
{
GrowList(outAttrListValueRefs, attrListValueRefListSize);
}
}
aChildPtr = aChildPtr->fNext;
}
} } } attrListRefIndex++;
aAttrListRefString = outAttrListRefs[attrListRefIndex];
}
}
fTableMutex.SignalLock();
}
void GrowList(char** &inOutRefs, UInt32 &inOutRefListSize)
{
UInt32 origSize = inOutRefListSize;
inOutRefListSize = inOutRefListSize * 2;
char** tempList = (char** )calloc(inOutRefListSize + 1, sizeof(char*));
memcpy(tempList, inOutRefs, origSize * sizeof(char *));
free(inOutRefs);
inOutRefs = tempList;
}
char* CRefTable::GetNodeName ( tDirReference inDirRef )
{
tDirStatus siResult = eDSNoErr;
sRefEntry *refData = nil;
char *outNodeName = nil;
siResult = GetReference( inDirRef, &refData );
if ( siResult == eDSNoErr )
{
outNodeName = refData->fNodeName;
}
return(outNodeName);
}