/*++ Copyright (C) Microsoft Corporation, 1990 - 1999 Module Name: util.c Abstract: This module provides all the utility functions for the Server side of the end-point mapper. Author: Bharat Shah Revision History: 06-03-97 gopalp Added code to cleanup stale EP Mapper entries. --*/ #include #include #include #include #include #include #include "epmp.h" #include "eptypes.h" #include "local.h" // // Link list manipulation rountines // #ifdef DBG void CountProcessContextList(EP_CLEANUP *pProcessContext, unsigned long nExpectedCount) { unsigned long nActualCount = 0; PIFOBJNode pNode = pProcessContext->EntryList; while (pNode && (pNode->OwnerOfList == pProcessContext)) { pNode = pNode->Next; nActualCount ++; } if (nActualCount != nExpectedCount) { DbgPrint("Expected count was %d, while actual count was %d\n", nExpectedCount, nActualCount); } } #endif PIENTRY Link( PIENTRY *Head, PIENTRY Node ) { if (Node == NULL) return (NULL); CheckInSem(); Node->Next = *Head; return(*Head = Node); } VOID LinkAtEnd( PIFOBJNode *Head, PIFOBJNode Node ) { register PIFOBJNode *ppNode; CheckInSem(); for ( ppNode = Head; *ppNode; ppNode = &((*ppNode)->Next) ); { ; // Empty body } *ppNode = Node; } PIENTRY UnLink( PIENTRY *Head, PIENTRY Node ) { PIENTRY *ppNode; for (ppNode = Head; *ppNode && (*ppNode != Node); ppNode = &(*ppNode)->Next) { ; // Empty body } if (*ppNode) { *ppNode = Node->Next; return (Node); } return (0); } PIFOBJNode GetLastIFOBJNode ( void ) /*++ Routine Description: Returns the address of the last PIFOBJNode Arguments: Return Value: See description. Notes: The IFObjList list MUST not be empty when this function is called. It will AV if the list is empty. Caller must verify that the list is not empty before calling this function. --*/ { PIFOBJNode CurrentNode = IFObjList; while (CurrentNode->Next != NULL) { CurrentNode = CurrentNode->Next; } return CurrentNode; } RPC_STATUS EnLinkOnIFOBJList( PEP_CLEANUP ProcessCtxt, PIFOBJNode NewNode ) /*++ Arguments: phContext - The context handle supplied by the process. NewNode - The node (EP entry) to be inserted into the EP Mapper database. Routine Description: This routine adds a new entry into the Endpoint Mapper database (which is maintained as a linked-list). It also updates the list of entries for the process identified by the context handle ProcessCtxt. Notes: a. This routine should always be called by holding a mutex. b. NewNode is already allocated by the caller. c. IFObjList may be created here. d. ProcessCtxt is assumed to be allocated sometime by the caler. Return Values: RPC_S_OK - Always. --*/ { RPC_STATUS Status = RPC_S_OK; IFOBJNode *LastNode; #ifdef DBG_DETAIL PIFOBJNode pTemp, pLast; #endif // DBG_DETAIL // Parameter validation. ASSERT(NewNode); ASSERT(ProcessCtxt); ASSERT(ProcessCtxt->MagicVal == CLEANUP_MAGIC_VALUE); ASSERT_PROCESS_CONTEXT_LIST_COUNT(ProcessCtxt, ProcessCtxt->cEntries); CheckInSem(); // // First, insert NewNode into this Process's list of entries. // NewNode->Next = ProcessCtxt->EntryList; if (ProcessCtxt->EntryList != NULL) { ASSERT(ProcessCtxt->cEntries > 0); ASSERT(cTotalEpEntries > 0); ASSERT(IFObjList != NULL); NewNode->Prev = ProcessCtxt->EntryList->Prev; // Next node's Prev pointer ProcessCtxt->EntryList->Prev = NewNode; if (NewNode->Prev) { ASSERT(cTotalEpEntries > 1); // Previous node's Next pointer NewNode->Prev->Next = NewNode; } } else { ASSERT(ProcessCtxt->cEntries == 0); NewNode->Prev = NULL; } // // Now, adjust the Global EP Mapper entries list head, if necessary // if (ProcessCtxt->EntryList != NULL) { if (ProcessCtxt->EntryList == IFObjList) { IFObjList = NewNode; } } else { // First entry registered by this process if (IFObjList != NULL) { LastNode = GetLastIFOBJNode(); ASSERT(LastNode != NULL); ASSERT(LastNode->Next == NULL); // Add the new ProcessCtxt at the tail of IFObjList LastNode->Next = NewNode; NewNode->Prev = LastNode; // should already have been set to NULL ASSERT(NewNode->Next == NULL); } else { ASSERT(cTotalEpEntries == 0); IFObjList = NewNode; } } // Add new node at the head of Process list. ProcessCtxt->EntryList = NewNode; NewNode->OwnerOfList = ProcessCtxt; ProcessCtxt->cEntries++; cTotalEpEntries++; #ifdef DBG_DETAIL DbgPrint("RPCSS: cTotalEpEntries++ [%p] (%d)\n", ProcessCtxt, cTotalEpEntries); DbgPrint("RPCSS: Dump of IFOBJList\n"); pTemp = IFObjList; pLast = IFObjList; while (pTemp) { DbgPrint("RPCSS: \t\t[%p]\n", pTemp); pLast = pTemp; pTemp = pTemp->Next; } DbgPrint("RPCSS: --------------------\n"); while (pLast) { DbgPrint("RPCSS: \t\t\t[%p]\n", pLast); pLast = pLast->Prev; } #endif // DBG_DETAIL ASSERT_PROCESS_CONTEXT_LIST_COUNT(ProcessCtxt, ProcessCtxt->cEntries); return (Status); } RPC_STATUS UnLinkFromIFOBJList( PEP_CLEANUP ProcessCtxt, PIFOBJNode DeleteMe ) /*++ Arguments: phContext - The context handle supplied by the process. DeleteMe - The node (EP entry) to be deleted from the EP Mapper database. Routine Description: This routine removes an existing entry from the Endpoint Mapper database (which is maintained as a linked-list). It also updates the list of entries for the process identified by the context handle ProcessCtxt. Notes: a. This routine should always be called by holding a mutex. b. DeleteMe node has to be freed by the caller. c. IFOBJlist may become empty (NULLed out) here. d. ProcessCtxt may become empty here and if so, it should be freed by the caller. Return Values: RPC_S_OK - If everyhing went well. RPC_S_ACCESS_DENIED - If something went wrong. --*/ { RPC_STATUS Status = RPC_S_OK; #ifdef DBG_DETAIL PIFOBJNode pTemp, pLast; #endif // DBG_DETAIL // Parameter validation. ASSERT(DeleteMe); ASSERT(ProcessCtxt); ASSERT(ProcessCtxt->MagicVal == CLEANUP_MAGIC_VALUE); CheckInSem(); // // The context has been created already for this process. So, there // should be one or more entries registered by this process. // ASSERT(IFObjList); ASSERT(cTotalEpEntries > 0); ASSERT(ProcessCtxt->EntryList); ASSERT(ProcessCtxt->cEntries > 0); ASSERT(ProcessCtxt->EntryList->OwnerOfList == ProcessCtxt); ASSERT_PROCESS_CONTEXT_LIST_COUNT(ProcessCtxt, ProcessCtxt->cEntries); // Trying to unregister someone else's entry? if (DeleteMe->OwnerOfList != ProcessCtxt) { ASSERT("Returning RPC_S_ACCESS_DENIED" && (DeleteMe->OwnerOfList != ProcessCtxt)); return (RPC_S_ACCESS_DENIED); } // // First, remove DeleteMe from this Process's List. // // See if it the first element of the process list. if (DeleteMe == ProcessCtxt->EntryList) { if (DeleteMe->Next) { // if we are nibbling the next segment, zero out the EntryList if (DeleteMe->Next->OwnerOfList != ProcessCtxt) { ProcessCtxt->EntryList = NULL; } else ProcessCtxt->EntryList = DeleteMe->Next; } else { ProcessCtxt->EntryList = NULL; } } ASSERT( ((ProcessCtxt->EntryList != NULL) && (ProcessCtxt->cEntries > 1)) || (ProcessCtxt->cEntries == 1) ); // Remove it. if (DeleteMe->Next != NULL) { // Next node's Prev pointer DeleteMe->Next->Prev = DeleteMe->Prev; } if (DeleteMe->Prev != NULL) { // Previous node's Next pointer DeleteMe->Prev->Next = DeleteMe->Next; } else { ASSERT(IFObjList == DeleteMe); } // // Next, adjust the Global EP Mapper entries list head, if necessary // if (IFObjList == DeleteMe) { // Can become NULL here. IFObjList = DeleteMe->Next; } // Remove node from all lists. DeleteMe->Prev = NULL; DeleteMe->Next = NULL; DeleteMe->OwnerOfList = NULL; ProcessCtxt->cEntries--; cTotalEpEntries--; #ifdef DBG_DETAIL DbgPrint("RPCSS: cTotalEpEntries-- [%p] (%d)\n", ProcessCtxt, cTotalEpEntries); DbgPrint("RPCSS: Dump of IFOBJList\n"); pTemp = IFObjList; pLast = IFObjList; while (pTemp) { DbgPrint("RPCSS: \t\t[%p]\n", pTemp); pLast = pTemp; pTemp = pTemp->Next; } DbgPrint("RPCSS: --------------------\n"); while (pLast) { DbgPrint("RPCSS: \t\t\t[%p]\n", pLast); pLast = pLast->Prev; } #endif // DBG_DETAIL ASSERT_PROCESS_CONTEXT_LIST_COUNT(ProcessCtxt, ProcessCtxt->cEntries); return (Status); } // // HACK Alert. // // Midl 1.00.xx didn't support full pointers. So, clients from NT 3.1 // machines will use unique pointers. This function detects and fixes // the buffer if an older client contacts our new server. // This HACK can be removed when supporting NT 3.1 era machines is no // longer required. void FixupForUniquePointerClients( PRPC_MESSAGE pRpcMessage ) { unsigned long *pBuffer = (unsigned long *)pRpcMessage->Buffer; // Check the obj uuid parameter. if (pBuffer[0] != 0) { // If it is not zero, it should be 1. pBuffer[0] = 1; // check the map_tower, which moves over 1 + 4 longs for the obj uuid if (pBuffer[5] != 0) pBuffer[5] = 2; } else { // Null obj uuid, check the map_tower. if (pBuffer[1] != 0) pBuffer[1] = 1; } }