//------------------------------------------------------------------- // Copyright (C) Microsoft Corporation, 1991 - 1999 // // mqmgr.c // // Abstract: // // Functions to manage temporary Falcon message queues for RPC. The // RPC support of Falcon as a transport allows for temporary queues // which exist only as long as the process. These functions manage // these temporary queues. // // Author: // // Edward Reus (edwardr) // // Revision History: // //------------------------------------------------------------------- #include #define FD_SETSIZE 1 #include #include #include #include #include #include #include #include #include "mqmgr.h" #define MAX_FORMAT_LEN 128 //------------------------------------------------------------------- // Local Types: //------------------------------------------------------------------- typedef struct _MqTempQueue { struct _MqTempQueue *pNext; WCHAR wsQFormat[MAX_FORMAT_LEN]; } MqTempQueue; typedef struct _MqTempQueueList { HANDLE hToken; // For impersonation of the client. MqTempQueue *pQueues; } MqTempQueueList; typedef HRESULT (APIENTRY *MQ_DELETE_QUEUE_FN)( WCHAR *pwsQFormat ); #define MQRT_DLL_NAME TEXT("MQRT.DLL") #define MQ_DELETE_FN_NAME "MQDeleteQueue" //------------------------------------------------------------------- // Globals: //------------------------------------------------------------------- static HINSTANCE g_hMqDll = 0; static MQ_DELETE_QUEUE_FN g_pMqDeleteQueue = 0; //------------------------------------------------------------------- // MqGetContext() // // Establishs a context handle to manage temporary queues. Once the // context handle is created, the RPC client and server processes // will automatically register temporary queues. //------------------------------------------------------------------- unsigned long MqGetContext( handle_t hBind, PCONTEXT_HANDLE *pphContext ) { RPC_STATUS Status = RPC_S_OK; HANDLE hToken = 0; HANDLE hThread = 0; MqTempQueueList *pqList; // First, check to see if the MQ runtime DLL has been loaded. If not, // then load it and resolve the entry for the function to delete queues. if (!g_hMqDll) { g_hMqDll = LoadLibrary(MQRT_DLL_NAME); if (g_hMqDll) { g_pMqDeleteQueue = (MQ_DELETE_QUEUE_FN)GetProcAddress(g_hMqDll,MQ_DELETE_FN_NAME); if (!g_pMqDeleteQueue) { Status = GetLastError(); FreeLibrary(g_hMqDll); g_hMqDll = 0; return Status; } } else { // The LoadLibrary() call failed. Status = GetLastError(); *pphContext = NULL; return Status; } } // Ok, create a context for this connection. Also, grab the // client's security token for later use when deleting the // queue. *pphContext = pqList = (MqTempQueueList*)I_RpcAllocate(sizeof(MqTempQueueList)); if (!*pphContext) { Status = RPC_S_OUT_OF_MEMORY; } else { ZeroMemory( pqList, sizeof(MqTempQueueList) ); Status = RpcImpersonateClient(hBind); if (RPC_S_OK == Status) { if ( (hThread=GetCurrentThread()) && (OpenThreadToken(hThread,TOKEN_IMPERSONATE,FALSE,&hToken)) ) { pqList->hToken = hToken; } else { Status = GetLastError(); } if (hThread) { CloseHandle(hThread); } Status = RpcRevertToSelf(); } else { // If the impersonation failed, then plow ahead anyway. We // can still keep the list of queues and "maybe" delete them. Status = RPC_S_OK; } } #ifdef DBG DbgPrint("MqGetContext(): hToken: 0x%x\n",hToken); #endif return Status; } //------------------------------------------------------------------- // MqRegisterQueue() // // Register the specified queue as a temporary queue that will // need to be deleted by the context rundown routine when the // client exits. The registration is actually done by the MQ RPC // client and server transport DLLs. //------------------------------------------------------------------- unsigned long MqRegisterQueue( PCONTEXT_HANDLE phContext, wchar_t *pwsQFormat ) { RPC_STATUS Status = RPC_S_OK; MqTempQueue *pTempQueue; MqTempQueueList *pqList = (MqTempQueueList*)phContext; pTempQueue = (MqTempQueue*)I_RpcAllocate(sizeof(MqTempQueue)); if (!pTempQueue) { return RPC_S_OUT_OF_MEMORY; } memset(pTempQueue,0,sizeof(MqTempQueue)); ASSERT(pwsQFormat); ASSERT(wcslen(pwsQFormat) < MAX_FORMAT_LEN); wcscpy(pTempQueue->wsQFormat,pwsQFormat); // Ok, put the queue on the list to delete. pTempQueue->pNext = pqList->pQueues; pqList->pQueues = pTempQueue; return Status; } //------------------------------------------------------------------- // MqDeregisterQueue() // // Remove the specified message queue from the list of queues to // be deleted by the context rundown routine. This would be done // if a queue (which is initially temporary) was turned into a // permanent queue. //------------------------------------------------------------------- unsigned long MqDeregisterQueue( PCONTEXT_HANDLE phContext, wchar_t *pwsQFormat ) { RPC_STATUS Status = RPC_S_OK; MqTempQueueList *pqList = (MqTempQueueList*)phContext; MqTempQueue *pTempQueue; MqTempQueue *pTempToFree; if (!pqList) { return RPC_X_SS_IN_NULL_CONTEXT; } pTempQueue = pqList->pQueues; if (!lstrcmpiW(pTempQueue->wsQFormat,pwsQFormat)) { pqList->pQueues = pTempQueue->pNext; I_RpcFree(pTempQueue); return RPC_S_OK; } while (pTempQueue->pNext) { if (!lstrcmpiW(pTempQueue->pNext->wsQFormat,pwsQFormat)) { pTempToFree = pTempQueue->pNext; pTempQueue->pNext = pTempQueue->pNext->pNext; I_RpcFree(pTempToFree); break; } } return Status; } //------------------------------------------------------------------- // MqFreeContext() // // Called to remove all of the queues registered for automatic // deletion and to close and free the context handle. //------------------------------------------------------------------- unsigned long MqFreeContext( PCONTEXT_HANDLE *pphContext, long fFreeContext ) { RPC_STATUS Status = RPC_S_OK; HRESULT hr; BOOL fImpersonate = FALSE; MqTempQueueList *pqList = (MqTempQueueList*)*pphContext; MqTempQueue *pTemp; MqTempQueue *pToFree; // First, impersonate the client who registered these queues // to delete. if (pqList->hToken) { fImpersonate = SetThreadToken(NULL,pqList->hToken); #ifdef DBG if (!fImpersonate) { Status = GetLastError(); } #endif } // Run through the list of queues deleting each one as // we go. pTemp = pqList->pQueues; while (pTemp) { pToFree = pTemp; pTemp = pTemp->pNext; hr = g_pMqDeleteQueue(pToFree->wsQFormat); #ifdef FALSE DbgPrint("Delete Queue: %S (hr: 0x%x)\n", pToFree->wsQFormat, hr ); #endif I_RpcFree(pToFree); } // Stop the impersonation: if (fImpersonate) { if (!SetThreadToken(NULL,NULL)) { Status = GetLastError(); } } // Do we need to free up the context? if (pqList->hToken) { if (!CloseHandle(pqList->hToken)) { Status = GetLastError(); #ifdef DBG DbgPrint("MqFreeContext(): CloseHandle() Failed: Status: %d (0x%x)\n",Status,Status); #endif } } if (fFreeContext) { I_RpcFree(pqList); *pphContext = NULL; } else { pqList->hToken = 0; pqList->pQueues = NULL; } return Status; } //------------------------------------------------------------------- // PCONTEX_HANDLE_rundown() // // This is the context rundown routine. It will delete all of the // Falcon message queues that are currently associated with the // specified context handle. //------------------------------------------------------------------- void __RPC_USER PCONTEXT_HANDLE_rundown( PCONTEXT_HANDLE phContext ) { RPC_STATUS Status; Status = MqFreeContext(&phContext,FALSE); } //------------------------------------------------------------------- // StartMqManagement() // // Called in dcomss\warpper\start.cxx by RPCSS to initialize the // MQ Management interface. //------------------------------------------------------------------- extern "C" DWORD StartMqManagement() { RPC_STATUS Status; Status = RpcServerRegisterIf(MqMgr_ServerIfHandle,0,0); return Status; }