/* * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /*! * @header CRefTable */ #include "CRefTable.h" #include "CLog.h" //DSSERVERTCP needed to direct TCP error logging #define DSSERVERTCP 1 #include "DSNetworkUtilities.h" #include #include #include #include // for struct kinfo_proc and sysctl() #include // for syslog() //-------------------------------------------------------------------------------------------------- // * Globals //-------------------------------------------------------------------------------------------------- //API logging extern dsBool gLogAPICalls; extern uInt32 gDaemonIPAddress; //------------------------------------------------------------------------------------ // * CRefTable //------------------------------------------------------------------------------------ CRefTable::CRefTable ( RefDeallocateProc *deallocProc ) { CFNumberRef aPIDCount = 0; CFStringRef aPIDString = 0; CFStringRef anIPString = 0; CFMutableArrayRef aClientPIDArray; uInt32 aCount = 0; CFMutableDictionaryRef aPIDDict = 0; fSunsetTime = time( nil); fClientPIDList = nil; fClientIPList = nil; fRefCleanUpEntriesHead = nil; fRefCleanUpEntriesTail = nil; fClientPIDListLock = new DSMutexSemaphore(); if (fClientPIDListLock != nil ) { fClientPIDListLock->Wait(); if (fClientIPList == nil) { fClientIPList = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); { fClientPIDList = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); aClientPIDArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); aPIDString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), getpid()); aPIDDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); aPIDCount = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&aCount); CFDictionarySetValue( aPIDDict, CFSTR("RefCount"), aPIDCount ); CFDictionarySetValue( fClientPIDList, aPIDString, aPIDDict ); CFArrayAppendValue(aClientPIDArray, aPIDString); CFDictionarySetValue( fClientPIDList, CFSTR("ClientPIDArray"), aClientPIDArray ); CFRelease(aPIDCount); CFRelease(aPIDDict); CFRelease(aClientPIDArray); CFRelease(aPIDString); } anIPString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), gDaemonIPAddress); CFDictionarySetValue( fClientIPList, anIPString, fClientPIDList ); CFRelease(anIPString); } fClientPIDListLock->Signal(); } fTableCount = 0; ::memset( fRefTables, 0, sizeof( fRefTables ) ); fDeallocProc = deallocProc; } // CRefTable //------------------------------------------------------------------------------------ // * ~CRefTable //------------------------------------------------------------------------------------ CRefTable::~CRefTable ( void ) { uInt32 i = 1; uInt32 j = 1; for ( i = 1; i <= kMaxTables; i++ ) //KW80 - note that array is still zero based even if first entry NOT used //-- added the last kMaxTable in the .h file so this should work now { 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 ] ); //KW80 need to free all the calloc'ed sRefEntries inside as well - code above fRefTables[ i ] = nil; } } if (fClientPIDListLock != nil) { fClientPIDListLock->Wait(); if (fClientIPList != nil) { CFRelease(fClientIPList); fClientIPList = 0; } fClientPIDListLock->Signal(); delete(fClientPIDListLock); fClientPIDListLock = nil; } } // ~CRefTable //-------------------------------------------------------------------------------------------------- // * Lock // //-------------------------------------------------------------------------------------------------- void CRefTable::Lock ( ) { fTableMutex.Wait(); } //-------------------------------------------------------------------------------------------------- // * Unlock // //-------------------------------------------------------------------------------------------------- void CRefTable::Unlock ( ) { fTableMutex.Signal(); } //-------------------------------------------------------------------------------------------------- // * VerifyReference // //-------------------------------------------------------------------------------------------------- tDirStatus CRefTable::VerifyReference ( tDirReference inDirRef, uInt32 inType, CServerPlugin **outPlugin, sInt32 inPID, uInt32 inIPAddress ) { tDirStatus siResult = eDSNoErr; sRefEntry *refData = nil; sPIDInfo *pPIDInfo = nil; siResult = GetReference( inDirRef, &refData ); //ref actually exists if ( siResult == eDSNoErr ) { //check if the type is correct if ( refData->fType != inType ) { siResult = eDSInvalidRefType; } else { //check the PIDs and IPAddresses here - both parent and child client ones siResult = eDSInvalidRefType; //parent client PID and IPAddress check if ( (refData->fPID == inPID) && (refData->fIPAddress == inIPAddress) ) { siResult = eDSNoErr; } else { //child clients PID and IPAddress check 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 ); } // VerifyReference //------------------------------------------------------------------------------------ // * VerifyDirRef (static) // //------------------------------------------------------------------------------------ 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 ); } // VerifyDirRef //------------------------------------------------------------------------------------ // * VerifyNodeRef (static) // //------------------------------------------------------------------------------------ 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 ); } // VerifyNodeRef //------------------------------------------------------------------------------------ // * VerifyRecordRef (static) // //------------------------------------------------------------------------------------ tDirStatus CRefTable::VerifyRecordRef ( tRecordReference inRecordRef, CServerPlugin **outPlugin, sInt32 inPID, uInt32 inIPAddress ) { tDirStatus siResult = eDSDirSrvcNotOpened; if ( gRefTable != nil ) { siResult = gRefTable->VerifyReference( inRecordRef, eRecordRefType, outPlugin, inPID, inIPAddress ); } return( siResult ); } // VerifyRecordRef //------------------------------------------------------------------------------------ // * VerifyAttrListRef (static) // //------------------------------------------------------------------------------------ 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 ); } // VerifyAttrListRef //------------------------------------------------------------------------------------ // * VerifyAttrValueRef (static) // //------------------------------------------------------------------------------------ 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 ); } // VerifyAttrValueRef //------------------------------------------------------------------------------------ // * NewDirRef //------------------------------------------------------------------------------------ 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 ); } // NewDirRef //------------------------------------------------------------------------------------ // * NewNodeRef //------------------------------------------------------------------------------------ tDirStatus CRefTable::NewNodeRef ( uInt32 *outNewRef, CServerPlugin *inPlugin, uInt32 inParentID, sInt32 inPID, uInt32 inIPAddress ) { tDirStatus siResult = eDSDirSrvcNotOpened; if ( gRefTable != nil ) { siResult = gRefTable->GetNewRef( outNewRef, inParentID, eNodeRefType, inPlugin, inPID, inIPAddress ); } return( siResult ); } // NewNodeRef //------------------------------------------------------------------------------------ // * NewRecordRef //------------------------------------------------------------------------------------ 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 ); } // NewRecordRef //------------------------------------------------------------------------------------ // * NewAttrListRef //------------------------------------------------------------------------------------ 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 ); } // NewAttrListRef //------------------------------------------------------------------------------------ // * NewAttrValueRef //------------------------------------------------------------------------------------ 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 ); } // NewAttrValueRef //------------------------------------------------------------------------------------ // * RemoveDirRef //------------------------------------------------------------------------------------ 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 ); } // RemoveDirRef //------------------------------------------------------------------------------------ // * RemoveNodeRef //------------------------------------------------------------------------------------ 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 ); } // RemoveNodeRef //------------------------------------------------------------------------------------ // * RemoveRecordRef //------------------------------------------------------------------------------------ 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 ); } // RemoveRecordRef //------------------------------------------------------------------------------------ // * RemoveAttrListRef //------------------------------------------------------------------------------------ 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 ); } // RemoveAttrListRef //------------------------------------------------------------------------------------ // * RemoveAttrValueRef //------------------------------------------------------------------------------------ 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 ); } // RemoveAttrValueRef //------------------------------------------------------------------------------------ // * SetNodePluginPtr //------------------------------------------------------------------------------------ tDirStatus CRefTable::SetNodePluginPtr ( tDirNodeReference inNodeRef, CServerPlugin *inPlugin ) { tDirStatus siResult = eDSDirSrvcNotOpened; if ( gRefTable != nil ) { siResult = gRefTable->SetPluginPtr( inNodeRef, eNodeRefType, inPlugin ); } return( siResult ); } // SetNodePluginPtr //------------------------------------------------------------------------------------ // * GetTableRef //------------------------------------------------------------------------------------ sRefEntry* CRefTable::GetTableRef ( uInt32 inRefNum ) { uInt32 uiSlot = 0; uInt32 uiRefNum = (inRefNum & 0x00FFFFFF); uInt32 uiTableNum = (inRefNum & 0xFF000000) >> 24; sRefTable *pTable = nil; sRefEntry *pOutEntry = nil; fTableMutex.Wait(); 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 ) { DBGLOG2( kLogAssert, "Reference %l error = %l", inRefNum, err ); } fTableMutex.Signal(); return( pOutEntry ); } // GetTableRef //------------------------------------------------------------------------------------ // * GetNextTable //------------------------------------------------------------------------------------ sRefTable* CRefTable::GetNextTable ( sRefTable *inTable ) { uInt32 uiTblNum = 0; sRefTable *pOutTable = nil; fTableMutex.Wait(); try { if ( inTable == nil ) { // Get the first reference table, create it if it wasn't already if ( fRefTables[ 1 ] == nil ) { // No tables have been allocated yet so lets make one 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 ) { // Set the table counter fTableCount = uiTblNum; // No tables have been allocated yet so lets make one 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 ) { DBGLOG1( kLogAssert, "Reference table error = %l", err ); } fTableMutex.Signal(); return( pOutTable ); } // GetNextTable //------------------------------------------------------------------------------------ // * GetThisTable //------------------------------------------------------------------------------------ sRefTable* CRefTable::GetThisTable ( uInt32 inTableNum ) { sRefTable *pOutTable = nil; fTableMutex.Wait(); pOutTable = fRefTables[ inTableNum ]; fTableMutex.Signal(); return( pOutTable ); } // GetThisTable //------------------------------------------------------------------------------------ // * GetNewRef //------------------------------------------------------------------------------------ tDirStatus CRefTable::GetNewRef ( uInt32 *outRef, uInt32 inParentID, eRefTypes inType, CServerPlugin *inPlugin, sInt32 inPID, uInt32 inIPAddress ) { 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.Wait(); 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 ) //KW80 - uiCntr was a condition never used //fixed below with uiCntr++; code addition { if ( (pCurTable->fCurRefNum == 0) || (pCurTable->fCurRefNum > 0x000FFFFF) ) { // Either it's the first reference for this table or we have // used 1024 * 1024 references and need to start over pCurTable->fCurRefNum = 1; } // Get the ref num and increment its place holder uiRefNum = pCurTable->fCurRefNum++; // Find a slot in the table for this ref number 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 ); // We found an empty slot, now set this table entry 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; // Add the table number to the reference number uiTableNum = (uiTableNum << 24); uiRefNum = uiRefNum | uiTableNum; *outRef = uiRefNum; // Up the item count pCurTable->fItemCnt++; outResult = eDSNoErr; done = true; if (inType == eDirectoryRefType) { refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, true, uiRefNum); } else { refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, true); } } uiCntr++; //KW80 needed for us to only go through the table once //ie the uiCntr does not get used directly BUT the uiRefNum gets //incremented only kMaxTableItems times since uiCntr is in the while condition } } } if ( inParentID != 0 ) { outResult = LinkToParent( *outRef, inType, inParentID, inPID, inIPAddress ); } } catch( sInt32 err ) { outResult = (tDirStatus)err; } fTableMutex.Signal(); return( outResult ); } // GetNewRef //------------------------------------------------------------------------------------ // * LinkToParent //------------------------------------------------------------------------------------ tDirStatus CRefTable::LinkToParent ( uInt32 inRefNum, uInt32 inType, uInt32 inParentID, sInt32 inPID, uInt32 inIPAddress ) { tDirStatus dsResult = eDSNoErr; sRefEntry *pCurrRef = nil; sListInfo *pChildInfo = nil; fTableMutex.Wait(); try { pCurrRef = GetTableRef( inParentID ); if ( pCurrRef == nil ) throw( (sInt32)eDSInvalidReference ); // This is the one we want pChildInfo = (sListInfo *)::calloc( sizeof( sListInfo ), sizeof( char ) ); if ( pChildInfo == nil ) throw( (sInt32)eDSRefTableAllocError ); // Save the info required later for removal if the parent gets removed pChildInfo->fRefNum = inRefNum; pChildInfo->fType = inType; pChildInfo->fPID = inPID; pChildInfo->fIPAddress = inIPAddress; // Set the link info pChildInfo->fNext = pCurrRef->fChildren; pCurrRef->fChildren = pChildInfo; } catch( sInt32 err ) { dsResult = (tDirStatus)err; } fTableMutex.Signal(); return( dsResult ); } // LinkToParent //------------------------------------------------------------------------------------ // * UnlinkFromParent //------------------------------------------------------------------------------------ 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.Wait(); try { //Node references are currently not linked to their parent dir reference //So, there is no issue when any child client PID has a reference linked to a parent since //it is unique to that child client PID and can be unlinked as before // Get the current reference pCurrRef = GetTableRef( inRefNum ); if ( pCurrRef == nil ) throw( (sInt32)eDSInvalidReference ); parentID = pCurrRef->fParentID; if ( parentID != 0 ) { // Get the parent reference pParentRef = GetTableRef( parentID ); if ( pParentRef == nil ) throw( (sInt32)eDSInvalidReference ); pCurrChild = pParentRef->fChildren; pPrevChild = pParentRef->fChildren; while ( pCurrChild != nil ) { //this will only work if no two or more children have the same ref number if ( pCurrChild->fRefNum == inRefNum ) { // Remove this node if ( i == 1 ) { // Link the next node to the base pointer pParentRef->fChildren = pCurrChild->fNext; } else { // Link the next node to the previous node pPrevChild->fNext = pCurrChild->fNext; } free( pCurrChild ); pCurrChild = nil; break; } pPrevChild = pCurrChild; pCurrChild = pCurrChild->fNext; i++; } } } catch( sInt32 err ) { dsResult = (tDirStatus)err; } fTableMutex.Signal(); return( dsResult ); } // UnlinkFromParent //------------------------------------------------------------------------------------ // * GetReference //------------------------------------------------------------------------------------ tDirStatus CRefTable::GetReference ( uInt32 inRefNum, sRefEntry **outRefData ) { tDirStatus dsResult = eDSNoErr; sRefEntry *pCurrRef = nil; fTableMutex.Wait(); try { pCurrRef = GetTableRef( inRefNum ); if ( pCurrRef == nil ) throw( (sInt32)eDSInvalidReference ); *outRefData = pCurrRef; } catch( sInt32 err ) { dsResult = (tDirStatus)err; } fTableMutex.Signal(); return( dsResult ); } // GetReference //------------------------------------------------------------------------------------ // * RemoveRef //------------------------------------------------------------------------------------ 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.Wait(); 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 ) // API refs have no parents { dsResult = UnlinkFromParent( inRefNum ); if ( dsResult != eDSNoErr ) throw( (sInt32)dsResult ); } pCurrRef = GetTableRef( inRefNum ); //KW80 - here we need to know where the sRefEntry is in the table to delete it //that is all the code added above // getting this sRefEntry is the same path used by uiSlot and pTable above if ( pCurrRef == nil ) throw( (sInt32)eDSInvalidReference ); if (inType != pCurrRef->fType) throw( (sInt32)eDSInvalidReference ); if ( pCurrRef->fChildren != nil ) { RemoveChildren( pCurrRef->fChildren, inPID, inIPAddress ); } //Now we check to see if this was a child or parent client PID and IPAddress that we removed - only applies to case of Node refs really if ( (pCurrRef->fPID == inPID) && (pCurrRef->fIPAddress == inIPAddress) ) { pCurrRef->fPID = -1; if (pCurrRef->fChildPID == nil) { doFree = true; } } else { pPIDInfo = pCurrRef->fChildPID; pPrevPIDInfo = pCurrRef->fChildPID; //remove all child client PIDs that match since all children refs for that PID removed already above //ie. within scope of a PID the refs are NOT ref counted while (pPIDInfo != nil) { if ( (pPIDInfo->fPID == inPID) && (pPIDInfo->fIPAddress == inIPAddress) ) { //need to remove this particular PID entry 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; } } //child client PIDs now removed so re-eval free if ( (pCurrRef->fPID == -1) && (pCurrRef->fChildPID == nil) ) { doFree = true; } } if (doFree) { if ( pTable->fTableData[ uiSlot ] != nil ) { if ( uiRefNum == pTable->fTableData[ uiSlot ]->fRefNum ) { // need to callback to make sure that the plug-ins clean up pCurrRef = pTable->fTableData[ uiSlot ]; pTable->fTableData[ uiSlot ] = nil; pTable->fItemCnt--; //set counter even if plugin itself fails to cleanup ie. tracking the ds server ref counts here specifically refCountUpdate = UpdateClientPIDRefCount(inPID, inIPAddress, false); if (fDeallocProc != nil) { //here we add the ref to be released in the plugin to our list of ref cleanup entries //note that since RemoveRef is potentially highly recursive we need to make these release calls later after //giving up the mutex for this ref table if (fRefCleanUpEntriesHead == nil) { //this is the first one fRefCleanUpEntriesHead = (sRefCleanUpEntry *)calloc(1, sizeof(sRefCleanUpEntry)); fRefCleanUpEntriesHead->fRefNum = inRefNum; //==pCurrRef->fRefNum 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; //==pCurrRef->fRefNum 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) //this tells us that we are at the top of the recursive stack in removing children and need to cleanup refs { aRefCleanUpEntriesIter = fRefCleanUpEntriesHead; fRefCleanUpEntriesHead = nil; fRefCleanUpEntriesTail = nil; } fTableMutex.Signal(); if (inbAtTop) //we can now clean up { while (aRefCleanUpEntriesIter != nil) { aRefCleanUpEntries = aRefCleanUpEntriesIter; if (aRefCleanUpEntries->fPlugin != nil) { //call the dealloc routine but don't bother to pass back the status deallocResult = (tDirStatus)(*fDeallocProc)( aRefCleanUpEntries->fRefNum, aRefCleanUpEntries->fType, aRefCleanUpEntries->fPlugin ); } aRefCleanUpEntriesIter = aRefCleanUpEntries->fNext; free(aRefCleanUpEntries); } } return( dsResult ); } // RemoveRef //------------------------------------------------------------------------------------ // * RemoveChildren //------------------------------------------------------------------------------------ void CRefTable::RemoveChildren ( sListInfo *inChildList, sInt32 inPID, uInt32 inIPAddress ) { sListInfo *pCurrChild = nil; sListInfo *pNextChild = nil; fTableMutex.Wait(); try { pCurrChild = inChildList; //walk the child list of refs while ( pCurrChild != nil ) { //we need to get the next entry first before RemoveRef since it will call UnlinkParent //which in turn will delete the current entry out from under us pNextChild = pCurrChild->fNext; //remove ref if it matches the inPID if ( ( pCurrChild->fPID == inPID ) && ( pCurrChild->fIPAddress == inIPAddress ) ) { RemoveRef( pCurrChild->fRefNum, pCurrChild->fType, inPID, inIPAddress, false ); } pCurrChild = pNextChild; } } catch( sInt32 err ) { } fTableMutex.Signal(); } // RemoveChildren //------------------------------------------------------------------------------------ // * SetPluginPtr //------------------------------------------------------------------------------------ tDirStatus CRefTable::SetPluginPtr ( uInt32 inRefNum, uInt32 inType, CServerPlugin *inPlugin ) { tDirStatus dsResult = eDSNoErr; sRefEntry *pCurrRef = nil; fTableMutex.Wait(); try { pCurrRef = GetTableRef( inRefNum ); if ( pCurrRef == nil ) throw( (sInt32)eDSInvalidReference ); if (inType != pCurrRef->fType) throw( (sInt32)eDSInvalidReference ); pCurrRef->fPlugin = inPlugin; } catch( sInt32 err ) { } fTableMutex.Signal(); return( dsResult ); } // SetPluginPtr //------------------------------------------------------------------------------------ // * AddChildPIDToRef (static) //------------------------------------------------------------------------------------ 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 ); // Save the info required for verification of ref pChildPIDInfo->fPID = inChildPID; pChildPIDInfo->fIPAddress = inIPAddress; // Set the link info pChildPIDInfo->fNext = pCurrRef->fChildPID; pCurrRef->fChildPID = pChildPIDInfo; } catch( sInt32 err ) { dsResult = (tDirStatus)err; } gRefTable->Unlock(); return( dsResult ); } // AddChildPIDToRef // ---------------------------------------------------------------------------- // * UpdateClientPIDRefCount() // // ---------------------------------------------------------------------------- uInt32 CRefTable:: UpdateClientPIDRefCount ( sInt32 inClientPID, uInt32 inIPAddress, bool inUpRefCount, uInt32 inDirRef ) { //if inUpRefCount is true then increment else decrement CFNumberRef aRefCount = 0; CFStringRef aComparePIDString = 0; CFStringRef aCompareIPString = 0; uInt32 aCount = 0; CFNumberRef aPIDCount = 0; CFMutableArrayRef aClientPIDArray; CFMutableDictionaryRef aPIDDict = 0; //what to do here: //lock list //check if list not nil //create compare pid string //check if PID already in dict //if in then get ref count and update //KW TODO if not in then add with ref count of one //unlock list fClientPIDListLock->Wait(); if (fClientIPList != nil) { aCompareIPString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), inIPAddress); aComparePIDString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), inClientPID); if ( (aCompareIPString != nil) && (aComparePIDString != nil) ) { if ( CFDictionaryContainsKey( fClientIPList, aCompareIPString ) ) { fClientPIDList = nil; fClientPIDList = (CFMutableDictionaryRef)CFDictionaryGetValue( fClientIPList, aCompareIPString ); if (fClientPIDList != nil) { //already have an entry if ( CFDictionaryContainsKey( fClientPIDList, aComparePIDString ) ) { aPIDDict = (CFMutableDictionaryRef)CFDictionaryGetValue( fClientPIDList, aComparePIDString ); aRefCount = (CFNumberRef)CFDictionaryGetValue( aPIDDict, CFSTR("RefCount") ); CFNumberGetValue(aRefCount, kCFNumberIntType, &aCount); if (inUpRefCount) { aCount++; if (gLogAPICalls) { syslog(LOG_INFO,"Client PID: %d, has %d open references.", inClientPID, aCount); } } else { aCount--; if (gLogAPICalls) { syslog(LOG_INFO,"Client PID: %d, has %d open references.", inClientPID, aCount); } } //let's remove it entirely from the list when there are no refs if (aCount == 0) { CFMutableArrayRef clientPIDArray = NULL; clientPIDArray = (CFMutableArrayRef)CFDictionaryGetValue(fClientPIDList, CFSTR("ClientPIDArray")); if (clientPIDArray != NULL) { int aPIDArrayCount = CFArrayGetCount( clientPIDArray ); for (CFIndex indexToPID=0; indexToPID < aPIDArrayCount; indexToPID++ ) { CFStringRef aStringRef = (CFStringRef)CFArrayGetValueAtIndex(clientPIDArray, indexToPID); if ( ( aStringRef != NULL ) && (kCFCompareEqualTo == CFStringCompare(aStringRef, aComparePIDString, 0)) ) { CFArrayRemoveValueAtIndex(clientPIDArray, indexToPID); //remove the dict entry as well CFDictionaryRemoveValue(fClientPIDList, aComparePIDString); break; } } } } //update since not zero else { //KW do I need to release the current CFNumberRef since I am creating a new one? //CFRelease(aRefCount); aRefCount = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&aCount); if (inDirRef != 0) //this should really only be for DS itself since we create the dict entry before we get a dir ref //OR a case where the dir ref is cleaned up and some ref is left over??? { if ( CFDictionaryContainsKey( aPIDDict, CFSTR("DirRefs")) ) { CFMutableArrayRef aDirRefArray = (CFMutableArrayRef)CFDictionaryGetValue(aPIDDict, CFSTR("DirRefs")); //add the dir ref to the array CFNumberRef aCFDirRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&inDirRef); CFArrayAppendValue(aDirRefArray, aCFDirRef); CFRelease(aCFDirRef); } else { //create a dir ref array CFMutableArrayRef aDirRefArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); //add the dir ref to the array CFNumberRef aCFDirRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&inDirRef); CFArrayAppendValue(aDirRefArray, aCFDirRef); CFDictionarySetValue( aPIDDict, CFSTR("DirRefs"), aDirRefArray ); CFRelease(aCFDirRef); CFRelease(aDirRefArray); } } //for all update the PID Count CFDictionaryReplaceValue(aPIDDict, CFSTR("RefCount"), aRefCount); CFRelease(aRefCount); } } //need to create a new entry only on the up count else if (inUpRefCount) { CFMutableArrayRef clientPIDArray; clientPIDArray = (CFMutableArrayRef)CFDictionaryGetValue(fClientPIDList, CFSTR("ClientPIDArray")); CFArrayAppendValue(clientPIDArray, aComparePIDString); aCount = 1; aRefCount = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&aCount); aPIDDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); CFDictionarySetValue( aPIDDict, CFSTR("RefCount"), aRefCount ); CFRelease(aRefCount); if (inDirRef != 0) { //create a dir ref array CFMutableArrayRef aDirRefArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); //add the dir ref to the array CFNumberRef aCFDirRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&inDirRef); CFArrayAppendValue(aDirRefArray, aCFDirRef); CFDictionarySetValue( aPIDDict, CFSTR("DirRefs"), aDirRefArray ); CFRelease(aCFDirRef); CFRelease(aDirRefArray); } CFDictionarySetValue( fClientPIDList, aComparePIDString, aPIDDict ); CFRelease(aPIDDict); } } } // if ( CFDictionaryContainsKey( fClientIPList, aCompareIPString ) ) else { fClientPIDList = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); aClientPIDArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); aPIDDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); if (inDirRef != 0) { //create a dir ref array CFMutableArrayRef aDirRefArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); //add the dir ref to the array CFNumberRef aCFDirRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&inDirRef); CFArrayAppendValue(aDirRefArray, aCFDirRef); CFDictionarySetValue( aPIDDict, CFSTR("DirRefs"), aDirRefArray ); aCount = 1; aPIDCount = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&aCount); CFDictionarySetValue( aPIDDict, CFSTR("RefCount"), aPIDCount ); CFDictionarySetValue( fClientPIDList, aComparePIDString, aPIDDict ); CFRelease(aCFDirRef); CFRelease(aDirRefArray); } CFArrayAppendValue(aClientPIDArray, aComparePIDString); CFDictionarySetValue( fClientPIDList, CFSTR("ClientPIDArray"), aClientPIDArray ); CFRelease(aPIDCount); CFRelease(aPIDDict); CFRelease(aClientPIDArray); CFDictionarySetValue( fClientIPList, aCompareIPString, fClientPIDList ); } CFRelease(aCompareIPString); CFRelease(aComparePIDString); } // if ( (aCompareIPString != nil) && (aComparePIDString != nil) ) } // if (fClientIPList != nil) fClientPIDListLock->Signal(); return aCount; } // UpdateClientPIDRefCount // ---------------------------------------------------------------------------- // * CheckClientPIDs() pass through static // // ---------------------------------------------------------------------------- void CRefTable::CheckClientPIDs ( bool inUseTimeOuts, uInt32 inIPAddress, uInt32 inPIDorPort ) { if (gRefTable != nil) { gRefTable->DoCheckClientPIDs(inUseTimeOuts, inIPAddress, inPIDorPort); } } // CheckClientPIDs // ---------------------------------------------------------------------------- // * DoCheckClientPIDs() //if inIPAddress is zero then a local cleanup check // // ---------------------------------------------------------------------------- void CRefTable::DoCheckClientPIDs ( bool inUseTimeOuts, uInt32 inIPAddress, uInt32 inPIDorPort ) { CFStringRef aPIDString = NULL; CFStringRef aCompareIPString = 0; char aStringBuff[16]; //sInt32 as string should be 11 chars max //this could be a PID or a Port uInt32 strBuffSize = 16; sInt32 aPIDValue = 0; CFNumberRef aRefCount = 0; uInt32 aCount = 0; size_t iSize = 0; register size_t i = 0; bool bPIDRunning = true; int mib [] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; size_t ulSize = 0; CFMutableDictionaryRef aPIDDict = NULL; uInt32 aDirRef = 0; CFStringRef aNullStringName = 0; CFIndex indexToPID = 0; sInt32 siResult = eDSNoErr; struct kinfo_proc *kpspArray = nil; sInt32 zeroVal = 0; bool bReloadDict = true; if (inUseTimeOuts) { if (::time( nil ) < fSunsetTime) { return; } } //wait one second since refs might be updated for other client PIDs if (fClientPIDListLock->Wait(1) != eDSNoErr) { fClientPIDListLock->Signal(); //ensure mutex is released return; } if (inIPAddress == 0) { //retrieve the process table for client PIDs // Allocate space for complete process list. if ( 0 > sysctl( mib, 4, NULL, &ulSize, NULL, 0) ) { fClientPIDListLock->Signal(); //ensure mutex is released return; //ie. do nothing } iSize = ulSize / sizeof(struct kinfo_proc); kpspArray = new kinfo_proc[ iSize ]; if (!kpspArray) { fClientPIDListLock->Signal(); //ensure mutex is released return; //ie. do nothing } // Get the proc list. ulSize = iSize * sizeof(struct kinfo_proc); if ( 0 > sysctl( mib, 4, kpspArray, &ulSize, NULL, 0 ) ) { delete [] kpspArray; fClientPIDListLock->Signal(); //ensure mutex is released return; //ie. do nothing } } //check if any client PID is no longer a process //can only look at PIDs that have the same IPAddress as this daemon ie. gDaemonIPAddress //if not then cleanup the references associated with that missing process //what to do here: //lock list //check if list not nil //loop over pids in the array within the list //each pid has refs since if zero in UpdateClientPIDRefCount method we take it out of the list //get all the pids from the process table and ... ????? //check if our pids are NOT in the process table //if they aren't then call cleanup functions for that pid - only need to call it on the DS references itself //since at that point all child refs will also be cleaned up //unlock the list if (fClientIPList != nil) { aNullStringName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), zeroVal); aCompareIPString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), inIPAddress); if ( (aNullStringName != nil) && (aCompareIPString != nil) ) { while (bReloadDict) { bReloadDict = false; if ( CFDictionaryContainsKey( fClientIPList, aCompareIPString ) ) { fClientPIDList = nil; fClientPIDList = (CFMutableDictionaryRef)CFDictionaryGetValue( fClientIPList, aCompareIPString ); if (fClientPIDList != nil) { CFMutableArrayRef clientPIDArray = NULL; clientPIDArray = (CFMutableArrayRef)CFDictionaryGetValue(fClientPIDList, CFSTR("ClientPIDArray")); if (clientPIDArray != NULL) { int aPIDArrayCount = CFArrayGetCount( clientPIDArray ); for (indexToPID=0; indexToPID < aPIDArrayCount; indexToPID++ ) { aPIDString = (CFStringRef)CFArrayGetValueAtIndex(clientPIDArray, indexToPID); if (aPIDString != NULL) { //getting a PID from the array means that there are refs left memset(aStringBuff, 0, strBuffSize); if ( CFStringGetCString( aPIDString, aStringBuff, strBuffSize, kCFStringEncodingUTF8 ) && (aStringBuff[0] != '\0') && (aStringBuff[strBuffSize] == '\0') ) { char *endPtr = nil; aPIDValue = (sInt32)strtol(aStringBuff, &endPtr, 10); //bPIDRunning set to false unless found in loop below bPIDRunning = false; if (inIPAddress == 0) { i = iSize; register struct kinfo_proc *kpsp = kpspArray; for ( ; i-- ; kpsp++ ) { // skip our own process //if ( kpsp->kp_proc.p_pid == ::getpid() ) //{ //continue; //} if (aPIDValue == kpsp->kp_proc.p_pid) { bPIDRunning = true; break; } } } else if ((uInt32)aPIDValue != inPIDorPort) { bPIDRunning = true; } if ( CFDictionaryContainsKey( fClientPIDList, aPIDString ) ) { aPIDDict = (CFMutableDictionaryRef)CFDictionaryGetValue( fClientPIDList, aPIDString ); if (aPIDDict != NULL) { aRefCount = (CFNumberRef)CFDictionaryGetValue( aPIDDict, CFSTR("RefCount") ); CFMutableArrayRef aDirRefArray = (CFMutableArrayRef)CFDictionaryGetValue(aPIDDict, CFSTR("DirRefs")); //don't believe aRefCount is retained so don't release CFNumberGetValue(aRefCount, kCFNumberIntType, &aCount); if (bPIDRunning) { if (gLogAPICalls) { syslog(LOG_INFO,"Client PID %d has ref count = %d",aPIDValue, aCount); } DBGLOG2( kLogHandler, "The client PID %d has ref count = %d.", aPIDValue, aCount ); } else { //KW issue when a client crashes and we are still servicing the call ie. using the refs //but here we want to clean up all the refs SO //need to wait (?) some cleanup time period greater than say 5 minutes (current mach timeout) //so that there will not be a deadlock on the use of the references when we want to remove them and //at the same time we are finishing out the processing for the client's call //can we simply put a timetag inside the dict and check it if it has expried so that we //can proceed with the cleanup //remove the entry from the dict CFRetain(aPIDDict); CFDictionaryRemoveValue(fClientPIDList, aPIDString); CFArraySetValueAtIndex(clientPIDArray, indexToPID, aNullStringName); fClientPIDListLock->Signal(); if (aDirRefArray != NULL) { //let's clean up this PID's references int aDirRefArrayCount = CFArrayGetCount( aDirRefArray ); for (CFIndex indexToDirRef=0; indexToDirRef < aDirRefArrayCount; indexToDirRef++ ) { //get the dir ref value CFNumberRef aCFDirRef= (CFNumberRef)CFArrayGetValueAtIndex( aDirRefArray, indexToDirRef ); CFNumberGetValue(aCFDirRef, kCFNumberIntType, &aDirRef); siResult = CRefTable::RemoveDirRef( aDirRef, aPIDValue, inIPAddress ); } }// if (aDirRefArray != NULL) fClientPIDListLock->Wait(); //KW for now output info always if (gLogAPICalls) { syslog(LOG_INFO,"Client PID %d had ref count = %d before cleanup.",aPIDValue, aCount); } DBGLOG2( kLogHandler, "The client PID %d had ref count = %d before cleanup.", aPIDValue, aCount ); CFRelease(aPIDDict); //let's reload the dict since we did some cleanup here and released the mutex //ie. start from the beginning above since something may have changed bReloadDict = true; break; } }// if (aPIDDict != NULL) } }// if (aStringBuff[0] != '\0') }// if (aPIDString != NULL) } // for (indexToPID=0; indexToPID < aPIDArrayCount; indexToPID++ ) //cleanup all the removed PIDs indexToPID = (CFArrayGetCount( clientPIDArray )) - 1; while (indexToPID > 0) //note index 0 points to this process so no need to check { if (kCFCompareEqualTo == CFStringCompare((CFStringRef)CFArrayGetValueAtIndex(clientPIDArray, indexToPID), aNullStringName, 0)) { CFArrayRemoveValueAtIndex(clientPIDArray, indexToPID); } indexToPID--; } }// if (clientPIDArray != NULL) } } } //while (bReloadDict) CFRelease(aNullStringName); CFRelease(aCompareIPString); }// if ( (aNullStringName != nil) && (aCompareIPString != nil) ) } // if (fClientIPList != nil) fSunsetTime = time(nil) + 300; fClientPIDListLock->Signal(); if (kpspArray != NULL) { delete [] kpspArray; } } // DoCheckClientPIDs