mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4613 lines
122 KiB
4613 lines
122 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
wmsgsvr.cxx
|
|
|
|
Abstract:
|
|
|
|
Implementation of the RPC on LPC (WMSG) protocol engine for the server.
|
|
|
|
Revision History:
|
|
Mazhar Mohammed: Code fork from spcsvr.cxx, 08/02/95
|
|
05-06-96: Merged WMSG and LRPC into a single protocol
|
|
|
|
--*/
|
|
|
|
#include <precomp.hxx>
|
|
#include <thrdctx.hxx>
|
|
#include <sdict2.hxx>
|
|
#include <hndlsvr.hxx>
|
|
#include <wmsgpack.hxx>
|
|
#include <wmsgsvr.hxx>
|
|
#include <wmsgclnt.hxx>
|
|
|
|
MSG_CACHE *MessageCache = NULL;
|
|
WMSG_SERVER *GlobalWMsgServer = NULL;
|
|
HINSTANCE hInstanceDLL ;
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
I_RpcSetOleCallback(
|
|
void * pfnCallback
|
|
)
|
|
{
|
|
InitializeIfNecessary();
|
|
|
|
if (InitializeWMsgIfNeccassary(0) != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("MSWMSG: InitializeWMsgIfNeccassary failed\n") ;
|
|
#endif
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
GlobalWMsgServer->SetOleCallback((POLEGETTID) pfnCallback) ;
|
|
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
I_RpcSetWMsgEndpoint (
|
|
IN RPC_CHAR PAPI * Endpoint
|
|
)
|
|
{
|
|
RPC_STATUS Status ;
|
|
|
|
Status = InitializeWMsgIfNeccassary(0) ;
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
return Status ;
|
|
}
|
|
|
|
ASSERT(MessageCache != 0) ;
|
|
ASSERT(GlobalWMsgServer != 0) ;
|
|
|
|
return GlobalWMsgServer->SetWMsgEndpoint(Endpoint) ;
|
|
}
|
|
|
|
|
|
inline void
|
|
RecvLotsaCallsWrapper(
|
|
WMSG_ADDRESS PAPI * Address
|
|
)
|
|
{
|
|
Address->ReceiveLotsaCalls();
|
|
}
|
|
|
|
|
|
LONG RPC_ENTRY
|
|
I_RpcWindowProc(
|
|
IN HWND hWnd,
|
|
IN UINT Message,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
WMSG_SASSOCIATION *Association ;
|
|
MSGMEM *pMsgMem ;
|
|
|
|
if (InitializeWMsgIfNeccassary(1) != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("MSWMSG: InitializeWMsgIfNeccassary failed\n") ;
|
|
#endif
|
|
}
|
|
|
|
switch(Message)
|
|
{
|
|
case WM_MSG_REQUEST:
|
|
if (LOWORD(wParam) == WMSG_MAGIC_VALUE)
|
|
{
|
|
pMsgMem = (MSGMEM *) lParam ;
|
|
Association = (WMSG_SASSOCIATION *) pMsgMem->Info.Association ;
|
|
|
|
ASSERT(Association) ;
|
|
|
|
(Association->InqAddress())->HandleRequest(
|
|
(WMSG_MESSAGE *) &(pMsgMem->WMSGMessage),
|
|
Association,
|
|
(RPC_MESSAGE *) &(pMsgMem->Info.RpcMessage),
|
|
pMsgMem->Info.Endpoint,
|
|
pMsgMem->Info.fSyncDispatch) ;
|
|
return 0;
|
|
}
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: This message is not ours !!\n") ;
|
|
#endif
|
|
break;
|
|
|
|
case WM_MSG_CALL_COMPLETE:
|
|
if (LOWORD(wParam) == WMSG_MAGIC_VALUE)
|
|
{
|
|
((WMSG_CCALL *) lParam)->CallCompleted() ;
|
|
((WMSG_CCALL *) lParam)->InqAssociation()->RemoveReference() ;
|
|
|
|
return 0;
|
|
}
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: This message is not ours !!\n") ;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return GlobalWMsgServer->DefWindowProcW (
|
|
hWnd, Message, wParam, lParam );
|
|
}
|
|
|
|
|
|
MSG_CACHE::MSG_CACHE(
|
|
)
|
|
{
|
|
unsigned int nIndex ;
|
|
MSGMEM *Message ;
|
|
|
|
for (nIndex = 0; nIndex < MSGCACHE_SIZE; nIndex++)
|
|
{
|
|
MessageTable[nIndex].WMSGMem.Info.RpcMessage.ReservedForRuntime =
|
|
&(MessageTable[nIndex].WMSGMem.Info.RuntimeInfo) ;
|
|
MessageTable[nIndex].WMSGMem.Info.Index = nIndex ;
|
|
MessageTable[nIndex].InUse = -1 ;
|
|
}
|
|
|
|
LastEntry = 0 ;
|
|
MessageCount = 0;
|
|
}
|
|
|
|
|
|
MSG_CACHE::~MSG_CACHE(
|
|
)
|
|
{
|
|
}
|
|
|
|
WMSG_MESSAGE *
|
|
MSG_CACHE::AllocateFromHeap(
|
|
)
|
|
{
|
|
MSGMEM *Message ;
|
|
|
|
Message = new MSGMEM ;
|
|
Message->Info.Index = MSGCACHE_SIZE ;
|
|
Message->Info.RpcMessage.ReservedForRuntime =
|
|
&(Message->Info.RuntimeInfo) ;
|
|
|
|
return (WMSG_MESSAGE *) Message ;
|
|
}
|
|
|
|
|
|
WMSG_MESSAGE *
|
|
MSG_CACHE::AllocateMessage(
|
|
)
|
|
{
|
|
int nIndex ;
|
|
WMSG_MESSAGE *Message = 0;
|
|
|
|
#if DBG
|
|
InterlockedIncrement(&MessageCount) ;
|
|
#endif
|
|
for (nIndex = LastEntry; nIndex < MSGCACHE_SIZE; nIndex++)
|
|
{
|
|
if (MessageTable[nIndex].InUse == -1)
|
|
{
|
|
if (InterlockedIncrement(&MessageTable[nIndex].InUse) == 0)
|
|
{
|
|
LastEntry = ((nIndex+1 == MSGCACHE_SIZE) ? 0 : nIndex+1) ;
|
|
Message = &(MessageTable[nIndex].WMSGMem.WMSGMessage);
|
|
|
|
goto end ;
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: lost the race, need to allocate message from cache\n") ;
|
|
#endif
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (nIndex = 0; nIndex < LastEntry; nIndex++)
|
|
{
|
|
if (MessageTable[nIndex].InUse == -1)
|
|
{
|
|
if (InterlockedIncrement(&MessageTable[nIndex].InUse) == 0)
|
|
{
|
|
LastEntry = ((nIndex+1 == MSGCACHE_SIZE) ? 0 : nIndex+1) ;
|
|
Message = &(MessageTable[nIndex].WMSGMem.WMSGMessage);
|
|
|
|
goto end ;
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: lost the race, need to allocate message from cache\n") ;
|
|
#endif
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: Cache is empty!! MessageCount=%d\n",
|
|
MessageCount) ;
|
|
#endif
|
|
|
|
Message = AllocateFromHeap() ;
|
|
if (Message == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
end:
|
|
Message->Rpc.RpcHeader.Flags = 0;
|
|
((MSGMEM *) Message)->Info.IsValid = TRUE ;
|
|
return Message;
|
|
}
|
|
|
|
|
|
void
|
|
MSG_CACHE::FreeMessage(
|
|
WMSG_MESSAGE *WMSGMessage
|
|
)
|
|
{
|
|
MSGMEM *Message ;
|
|
|
|
#if DBG
|
|
InterlockedDecrement(&MessageCount) ;
|
|
#endif
|
|
ASSERT(VALID_MESSAGE(WMSGMessage)) ;
|
|
Message = (MSGMEM *) WMSGMessage ;
|
|
Message->Info.IsValid = FALSE ;
|
|
|
|
if (Message->Info.Index < MSGCACHE_SIZE)
|
|
{
|
|
MessageTable[Message->Info.Index].InUse = -1 ;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(Message->Info.Index == MSGCACHE_SIZE) ;
|
|
delete Message ;
|
|
}
|
|
}
|
|
|
|
|
|
THREAD_IDENTIFIER stub_OLEGETTID (IN UUID *pUUID)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->OleGetTid(pUUID) ;
|
|
}
|
|
|
|
LRESULT
|
|
WINAPI stub_DEFWINDOWPROC (
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->DefWindowProcW(hWnd, Msg, wParam, lParam) ;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI stub_POSTMESSAGE (
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->PostMessageW(hWnd, Msg, wParam, lParam) ;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI stub_PEEKMESSAGE (
|
|
LPMSG lpMsg,
|
|
HWND hWnd ,
|
|
UINT wMsgFilterMin,
|
|
UINT wMsgFilterMax,
|
|
UINT wRemoveMsg)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->PeekMessageW(lpMsg, hWnd, wMsgFilterMin,
|
|
wMsgFilterMax, wRemoveMsg) ;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI stub_TRANSLATEMESSAGE (
|
|
CONST MSG *lpMsg)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->TranslateMessage(lpMsg) ;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI stub_MSGWAIT (
|
|
DWORD nCount,
|
|
LPHANDLE pHandles,
|
|
BOOL fWaitAll,
|
|
DWORD dwMilliseconds,
|
|
DWORD dwWakeMask)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->MsgWaitForMultipleObjects(nCount, pHandles,
|
|
fWaitAll, dwMilliseconds, dwWakeMask) ;
|
|
}
|
|
|
|
LRESULT
|
|
WINAPI stub_SENDMESSAGE (
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->SendMessageW(hWnd, Msg, wParam, lParam) ;
|
|
}
|
|
|
|
LONG
|
|
WINAPI stub_DISPATCHMESSAGE (
|
|
CONST MSG *lpMsg)
|
|
{
|
|
if (GlobalWMsgServer->ActuallyInitializeWMsgServer() != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: stub failed to initalize WMSG_SERVER\n") ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
return GlobalWMsgServer->DispatchMessageW(lpMsg) ;
|
|
}
|
|
|
|
|
|
|
|
WMSG_SERVER::WMSG_SERVER(
|
|
IN OUT RPC_STATUS PAPI *RpcStatus
|
|
) : ServerMutex(RpcStatus)
|
|
{
|
|
Address = NULL ;
|
|
|
|
pDefWindowProc = stub_DEFWINDOWPROC ;
|
|
pPostMessage = stub_POSTMESSAGE ;
|
|
pPeekMessage = stub_PEEKMESSAGE ;
|
|
pTranslateMessage = stub_TRANSLATEMESSAGE ;
|
|
pMsgWaitForMultipleObjects = stub_MSGWAIT ;
|
|
pSendMessage = stub_SENDMESSAGE ;
|
|
pDispatchMessage = stub_DISPATCHMESSAGE ;
|
|
pOleGetTid = stub_OLEGETTID ;
|
|
ActuallyInitialized = 0 ;
|
|
wmsgEndpointInitialized = 0 ;
|
|
}
|
|
|
|
|
|
WMSG_SERVER::~WMSG_SERVER(
|
|
)
|
|
{
|
|
if (hOle32 != NULL)
|
|
{
|
|
FreeLibrary(hOle32) ;
|
|
}
|
|
|
|
if (hUser32 != NULL)
|
|
{
|
|
FreeLibrary(hUser32) ;
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SERVER::ActuallyInitializeWMsgServer(
|
|
)
|
|
{
|
|
WNDCLASSW wc;
|
|
|
|
GlobalMutexRequest() ;
|
|
|
|
if (ActuallyInitialized == 0)
|
|
{
|
|
hOle32 = LoadLibraryW(RPC_CONST_STRING("ole32.dll")) ;
|
|
if (hOle32 == NULL)
|
|
{
|
|
GlobalMutexClear() ;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
if (pOleGetTid == stub_OLEGETTID)
|
|
{
|
|
pOleGetTid = (POLEGETTID) GetProcAddress(hOle32,
|
|
"CoGetTIDFromIPID") ;
|
|
if (pOleGetTid == NULL)
|
|
{
|
|
GlobalMutexClear() ;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
}
|
|
|
|
hUser32 = LoadLibraryW(RPC_CONST_STRING("user32.dll")) ;
|
|
if (hUser32 == NULL)
|
|
{
|
|
GlobalMutexClear() ;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
pDefWindowProc =
|
|
(PDEFWINDOWPROC) GetProcAddress(hUser32,"DefWindowProcW");
|
|
pPostMessage =
|
|
(PPOSTMESSAGE) GetProcAddress(hUser32,"PostMessageW") ;
|
|
pPeekMessage =
|
|
(PPEEKMESSAGE) GetProcAddress(hUser32,"PeekMessageW") ;
|
|
pTranslateMessage =
|
|
(PTRANSLATEMESSAGE) GetProcAddress(hUser32,"TranslateMessage") ;
|
|
pMsgWaitForMultipleObjects =
|
|
(PMSGWAIT) GetProcAddress(hUser32,"MsgWaitForMultipleObjects") ;
|
|
pSendMessage =
|
|
(PSENDMESSAGE) GetProcAddress(hUser32,"SendMessageW") ;
|
|
pDispatchMessage =
|
|
(PDISPATCHMESSAGE) GetProcAddress(hUser32,"DispatchMessageW") ;
|
|
|
|
if ((pDefWindowProc == NULL) ||
|
|
(pPeekMessage == NULL) ||
|
|
(pTranslateMessage == NULL) ||
|
|
(pMsgWaitForMultipleObjects == NULL) ||
|
|
(pSendMessage == NULL) ||
|
|
(pDispatchMessage == NULL)
|
|
)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: GetProcAddress failed\n") ;
|
|
#endif
|
|
GlobalMutexClear() ;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
ActuallyInitialized = 1 ;
|
|
}
|
|
|
|
GlobalMutexClear() ;
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SERVER::ServerStartingToListen (
|
|
HWND hWnd
|
|
)
|
|
{
|
|
THREAD *pThread ;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
THREAD_IDENTIFIER tid ;
|
|
WMSG_ENDPOINT *Endpoint ;
|
|
|
|
// get thread id
|
|
tid = GetThreadIdentifier() ;
|
|
|
|
Endpoint = WMsgEndpointDict.Find(tid) ;
|
|
if (Endpoint == 0)
|
|
{
|
|
// create a THREAD object
|
|
pThread = new THREAD(&Status) ;
|
|
if (pThread == NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
|
|
ASSERT(Status == RPC_S_OK) ;
|
|
|
|
Endpoint = new WMSG_ENDPOINT(tid, pThread, hWnd) ;
|
|
if (Endpoint == NULL)
|
|
{
|
|
delete pThread ;
|
|
RpcpSetThreadPointer(0) ;
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
|
|
// add the window and pointer to the thread object and thread id
|
|
// to the dictionary
|
|
if (WMsgEndpointDict.Insert(tid, Endpoint) == -1)
|
|
{
|
|
delete pThread ;
|
|
delete Endpoint ;
|
|
RpcpSetThreadPointer(0) ;
|
|
return (RPC_S_OUT_OF_MEMORY) ; // BUGBUG: cleanup here
|
|
}
|
|
}
|
|
|
|
Endpoint->StartListening() ;
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SERVER::ServerStoppedListening (
|
|
)
|
|
{
|
|
THREAD_IDENTIFIER tid ;
|
|
WMSG_ENDPOINT *Endpoint ;
|
|
MSG wMsg ;
|
|
HWND hWnd ;
|
|
int i = 5;
|
|
|
|
// get thread id
|
|
tid = GetThreadIdentifier() ;
|
|
|
|
ServerMutex.Request() ;
|
|
|
|
// lookup entry using threadid
|
|
Endpoint = WMsgEndpointDict.Find(tid) ;
|
|
if (Endpoint == 0)
|
|
{
|
|
ServerMutex.Clear() ;
|
|
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
|
|
// delete the dictionary entry
|
|
WMsgEndpointDict.Delete(tid) ;
|
|
|
|
ServerMutex.Clear() ;
|
|
|
|
Endpoint->StopListening() ;
|
|
|
|
|
|
hWnd = Endpoint->InqhWnd() ;
|
|
|
|
while (i && Endpoint->callcount != 0)
|
|
{
|
|
i-- ;
|
|
while (GlobalWMsgServer->PeekMessageW(&wMsg, hWnd, 0, 0, PM_REMOVE))
|
|
{
|
|
GlobalWMsgServer->TranslateMessage(&wMsg);
|
|
GlobalWMsgServer->DispatchMessageW(&wMsg);
|
|
}
|
|
Sleep(1000) ;
|
|
}
|
|
|
|
// delete the thread object
|
|
delete Endpoint->InqThread() ;
|
|
RpcpSetThreadPointer(0) ;
|
|
|
|
delete Endpoint ;
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
RPC_STATUS
|
|
InitializeWMsg(
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus = RPC_S_OK ;
|
|
|
|
GlobalMutexRequest() ;
|
|
|
|
if (GlobalWMsgServer == 0)
|
|
{
|
|
GlobalWMsgServer = new WMSG_SERVER(&RpcStatus) ;
|
|
|
|
if (GlobalWMsgServer == 0)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: WMSG_SERVER initialization failed\n") ;
|
|
#endif
|
|
GlobalMutexClear() ;
|
|
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
delete GlobalWMsgServer ;
|
|
GlobalWMsgServer = 0 ;
|
|
|
|
return RpcStatus ;
|
|
}
|
|
}
|
|
|
|
if (MessageCache == 0)
|
|
{
|
|
MessageCache = new MSG_CACHE() ;
|
|
|
|
if (MessageCache == 0)
|
|
{
|
|
GlobalMutexClear() ;
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
}
|
|
|
|
GlobalMutexClear() ;
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
I_RpcServerStartListening(
|
|
HWND hWnd
|
|
)
|
|
{
|
|
RPC_STATUS Status ;
|
|
|
|
Status = InitializeWMsgIfNeccassary(1) ;
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
return Status ;
|
|
}
|
|
|
|
ASSERT(GlobalWMsgServer != 0) ;
|
|
|
|
return GlobalWMsgServer->ServerStartingToListen(hWnd) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
I_RpcServerStopListening(
|
|
)
|
|
{
|
|
RPC_STATUS Status ;
|
|
|
|
Status = InitializeWMsgIfNeccassary(1) ;
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
return Status ;
|
|
}
|
|
|
|
ASSERT(GlobalWMsgServer != 0) ;
|
|
|
|
return GlobalWMsgServer->ServerStoppedListening() ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
I_RpcGetThreadWindowHandle(
|
|
OUT HWND *WindowHandle
|
|
)
|
|
{
|
|
RPC_STATUS Status ;
|
|
|
|
Status = InitializeWMsgIfNeccassary(1) ;
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
return Status ;
|
|
}
|
|
|
|
ASSERT(GlobalWMsgServer != 0) ;
|
|
|
|
return GlobalWMsgServer->GetThreadWindowHandle(WindowHandle) ;
|
|
}
|
|
|
|
|
|
void SetFaultPacket(
|
|
IN WMSG_MESSAGE *WMSGMessage,
|
|
IN RPC_STATUS Status,
|
|
IN BOOL IsWMsg,
|
|
IN int Flags
|
|
)
|
|
{
|
|
WMSGMessage->Fault.RpcHeader.MessageType = WMSG_MSG_FAULT;
|
|
WMSGMessage->Fault.RpcStatus = Status;
|
|
WMSGMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_FAULT_MESSAGE)
|
|
- sizeof(PORT_MESSAGE);
|
|
|
|
if (IsWMsg && ((Flags & WMSG_SYNC_CLIENT) == 0))
|
|
{
|
|
WMSGMessage->LpcHeader.u2.ZeroInit = 0;
|
|
WMSGMessage->LpcHeader.MessageId = 0;
|
|
WMSGMessage->LpcHeader.CallbackId = 0;
|
|
WMSGMessage->LpcHeader.u2.s2.DataInfoOffset = 0;
|
|
}
|
|
}
|
|
|
|
|
|
WMSG_ADDRESS::WMSG_ADDRESS (
|
|
OUT RPC_STATUS * RpcStatus
|
|
) : RPC_ADDRESS(RpcStatus)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
LpcAddressPort = 0;
|
|
CallThreadCount = 0;
|
|
ActiveCallCount = 0;
|
|
ServerListeningFlag = 0;
|
|
fSpareThread = 0;
|
|
AssociationCount = 0;
|
|
WMSGCallCount = 0;
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::WaitForCalls(
|
|
)
|
|
{
|
|
MSG wMsg ;
|
|
|
|
while (InqNumberOfActiveCalls() > AutoListenCallCount.GetInteger())
|
|
{
|
|
if (GlobalWMsgServer->PeekMessageW(&wMsg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
GlobalWMsgServer->TranslateMessage(&wMsg);
|
|
GlobalWMsgServer->DispatchMessageW(&wMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::HandleRequest (
|
|
IN WMSG_MESSAGE *WMSGMessage,
|
|
IN WMSG_SASSOCIATION * Association,
|
|
IN PRPC_MESSAGE RpcMessage,
|
|
IN WMSG_ENDPOINT *Endpoint,
|
|
IN BOOL fSyncDispatch
|
|
)
|
|
{
|
|
NTSTATUS NtStatus ;
|
|
WMSG_MESSAGE *WMSGReply ;
|
|
THREAD_IDENTIFIER tid ;
|
|
WMSG_SBINDING *SBinding = 0;
|
|
int Flags = WMSGMessage->Rpc.RpcHeader.Flags ;
|
|
int fSyncClient = 0;
|
|
|
|
if (Flags & WMSG_SYNC_CLIENT)
|
|
{
|
|
fSyncClient = 1;
|
|
}
|
|
|
|
ASSERT(VALID_MESSAGE(WMSGMessage)) ;
|
|
|
|
if (Association->IsAborted() == 0)
|
|
{
|
|
WMSGReply = MessageCache->AllocateMessage() ;
|
|
|
|
// we do not need to acquire the ServerMutex to access the Endpoint
|
|
// object. This is because the Endpoint object already has positive
|
|
// refcount and it will not get deleted until it is 0
|
|
|
|
if (WMSGReply == NULL ||
|
|
(ServerListeningFlag == 0 &&
|
|
GlobalRpcServer->InqNumAutoListenInterfaces() == 0) ||
|
|
(Endpoint && Endpoint->ThreadListening() == 0))
|
|
{
|
|
if (!(Flags & DISPATCH_ASYNC))
|
|
{
|
|
SetFaultPacket(WMSGMessage, RPC_S_SERVER_TOO_BUSY,
|
|
TRUE, Flags) ;
|
|
|
|
NtStatus = Association->ReplyMessage(WMSGMessage, Flags) ;
|
|
if (NT_ERROR(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: ReplyMessage failed\n") ;
|
|
#endif
|
|
Association->AbortAssociation() ;
|
|
}
|
|
}
|
|
|
|
if (WMSGReply != NULL)
|
|
{
|
|
MessageCache->FreeMessage(WMSGReply) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(VALID_MESSAGE(WMSGMessage)) ;
|
|
ASSERT(VALID_MESSAGE(WMSGReply)) ;
|
|
ASSERT(WMSGMessage != WMSGReply) ;
|
|
|
|
Association->DealWithRequestMessage( WMSGMessage,WMSGReply,
|
|
RpcMessage,&SBinding,
|
|
Flags, TRUE, fSyncClient) ;
|
|
|
|
if (!(Flags & DISPATCH_ASYNC))
|
|
{
|
|
WMSGReply->Rpc.RpcHeader.ConnectionKey =
|
|
WMSGMessage->Rpc.RpcHeader.ConnectionKey ;
|
|
|
|
if (fSyncClient)
|
|
{
|
|
WMSGReply->LpcHeader.ClientId =
|
|
WMSGMessage->LpcHeader.ClientId ;
|
|
WMSGReply->LpcHeader.CallbackId =
|
|
WMSGMessage->LpcHeader.CallbackId ;
|
|
WMSGReply->LpcHeader.MessageId =
|
|
WMSGMessage->LpcHeader.MessageId ;
|
|
WMSGReply->LpcHeader.u2.s2.DataInfoOffset =
|
|
WMSGMessage->LpcHeader.u2.s2.DataInfoOffset ;
|
|
}
|
|
|
|
// we only care about the common case,
|
|
// so we will only optimize for that
|
|
NtStatus = Association->ReplyMessage(WMSGReply, Flags) ;
|
|
if (NT_ERROR(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: ReplyMessage failed\n") ;
|
|
#endif
|
|
|
|
Association->AbortAssociation() ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//BUGBUG:
|
|
// free any output buffer...
|
|
}
|
|
|
|
MessageCache->FreeMessage(WMSGReply) ;
|
|
}
|
|
}
|
|
|
|
if (SBinding)
|
|
{
|
|
SBinding->RpcInterface->EndAutoListenCall() ;
|
|
}
|
|
|
|
AddressMutex.Request();
|
|
ActiveCallCount -= 1;
|
|
AutoListenCallCount.Decrement();
|
|
if (fSyncDispatch)
|
|
{
|
|
CallThreadCount -= 1;
|
|
}
|
|
else
|
|
{
|
|
WMSGCallCount -= 1;
|
|
}
|
|
AddressMutex.Clear() ;
|
|
|
|
if (Endpoint)
|
|
{
|
|
Endpoint->EndCall() ;
|
|
}
|
|
MessageCache->FreeMessage(WMSGMessage) ;
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_ADDRESS::FireUpManager (
|
|
IN unsigned int MinimumConcurentCalls
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We fire up the manager in this method. To even get started, we need
|
|
to create at least one thread; we will do this now.
|
|
|
|
Arguments:
|
|
|
|
MinimumConcurentCalls - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully fired up the manager.
|
|
|
|
RPC_S_OUT_OF_THREADS - We could not create one thread.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
AddressMutex.Request();
|
|
|
|
RpcStatus = Server->CreateThread(
|
|
(THREAD_PROC)&RecvLotsaCallsWrapper,
|
|
this
|
|
);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
AddressMutex.Clear();
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_THREADS );
|
|
return(RpcStatus);
|
|
}
|
|
|
|
CallThreadCount += 1;
|
|
this->MinimumCallThreads = 1;
|
|
|
|
AddressMutex.Clear();
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_ADDRESS::ServerStartingToListen (
|
|
IN unsigned int MinimumCallThreads,
|
|
IN unsigned int MaximumConcurrentCalls,
|
|
IN int ServerThreadsStarted
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets called when RpcServerListen is called by the application.
|
|
We need to create the threads we need to receive remote procedure calls.
|
|
|
|
Arguments:
|
|
|
|
MinimumCallThreads - Supplies the minimum number of threads which we
|
|
must create.
|
|
|
|
MaximumConcurrentCalls - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Ok, this address is all ready to start listening for remote
|
|
procedure calls.
|
|
|
|
RPC_S_OUT_OF_THREADS - We could not create enough threads so that we
|
|
have at least the minimum number of call threads required (as
|
|
specified by the MinimumCallThreads argument).
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
UNUSED(MaximumConcurrentCalls);
|
|
|
|
if (ServerThreadsStarted == 0)
|
|
{
|
|
this->MinimumCallThreads = MinimumCallThreads;
|
|
AddressMutex.Request();
|
|
if (CallThreadCount < this->MinimumCallThreads)
|
|
{
|
|
RpcStatus = Server->CreateThread(
|
|
(THREAD_PROC)&RecvLotsaCallsWrapper,
|
|
this
|
|
);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
AddressMutex.Clear();
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_THREADS );
|
|
return(RpcStatus);
|
|
}
|
|
CallThreadCount += 1;
|
|
}
|
|
AddressMutex.Clear();
|
|
}
|
|
|
|
ServerListeningFlag = 1;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::ServerStoppedListening (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We just need to indicate that the server is no longer listening, and
|
|
set the minimum call thread count to one.
|
|
|
|
--*/
|
|
{
|
|
ServerListeningFlag = 0;
|
|
MinimumCallThreads = 1;
|
|
}
|
|
|
|
|
|
unsigned int
|
|
WMSG_ADDRESS::InqNumberOfActiveCalls (
|
|
)
|
|
/*++
|
|
|
|
Return Value:
|
|
|
|
The number of active calls on this address will be returned.
|
|
|
|
--*/
|
|
{
|
|
return(ActiveCallCount);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_ADDRESS::SetupAddressWithEndpoint (
|
|
IN RPC_CHAR PAPI * Endpoint,
|
|
OUT RPC_CHAR PAPI * PAPI * NetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN void PAPI * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence,
|
|
IN unsigned long EndpointFlags,
|
|
IN unsigned long NICFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to setup the connection port and get ready to receive remote
|
|
procedure calls. We will use the name of this machine as the network
|
|
address.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Supplies the endpoint to be used will this address.
|
|
|
|
NetworkAddress - Returns the network address for this server. The
|
|
ownership of the buffer allocated to contain the network address
|
|
passes to the caller.
|
|
|
|
SecurityDescriptor - Optionally supplies a security descriptor to
|
|
be placed on this address.
|
|
|
|
PendingQueueSize - Unused.
|
|
|
|
RpcProtocolSequence - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully setup this address.
|
|
|
|
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
|
|
invalid.
|
|
|
|
RPC_S_CANT_CREATE_ENDPOINT - The endpoint format is correct, but
|
|
the endpoint can not be created.
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint is not a valid
|
|
endpoint for this particular transport interface.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|
setup the address.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to setup
|
|
the address.
|
|
|
|
--*/
|
|
{
|
|
DWORD NetworkAddressLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
BOOL Boolean;
|
|
RPC_CHAR * LpcPortName;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS NtStatus;
|
|
RPC_STATUS Status ;
|
|
char * PAPI *tmpPtr ;
|
|
|
|
UNUSED(PendingQueueSize);
|
|
UNUSED(RpcProtocolSequence);
|
|
|
|
fSpareThread = (PendingQueueSize > RPC_C_PROTSEQ_MAX_REQS_DEFAULT);
|
|
|
|
Status = InitializeWMsgIfNeccassary(0) ;
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
return Status ;
|
|
}
|
|
|
|
ASSERT(MessageCache != 0) ;
|
|
ASSERT(GlobalWMsgServer != 0) ;
|
|
|
|
*NumNetworkAddress = 1 ;
|
|
|
|
*NetworkAddress = new RPC_CHAR[MAX_COMPUTERNAME_LENGTH + 5];
|
|
if ( *NetworkAddress == 0 )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
tmpPtr = (char * PAPI *) *NetworkAddress ;
|
|
|
|
tmpPtr[0] = (char *) *NetworkAddress + sizeof (RPC_CHAR *) ;
|
|
|
|
Boolean = GetComputerNameW((RPC_CHAR *) tmpPtr[0], &NetworkAddressLength);
|
|
|
|
#if DBG
|
|
|
|
if ( Boolean != TRUE )
|
|
{
|
|
PrintToDebugger("RPC : GetComputerNameW : %d\n", GetLastError());
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( Boolean == TRUE );
|
|
|
|
// Allocate and initialize the port name. We need to stick the
|
|
// WMSG_DIRECTORY_NAME on the front of the endpoint. This is for
|
|
// security reasons (so that anyone can create WMSG endpoints).
|
|
|
|
LpcPortName = new RPC_CHAR[RpcpStringLength(Endpoint)
|
|
+ RpcpStringLength(WMSG_DIRECTORY_NAME) + 1];
|
|
if ( LpcPortName == 0 )
|
|
{
|
|
delete *NetworkAddress;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
RpcpMemoryCopy(LpcPortName, WMSG_DIRECTORY_NAME,
|
|
RpcpStringLength(WMSG_DIRECTORY_NAME) * sizeof(RPC_CHAR));
|
|
RpcpMemoryCopy(LpcPortName + RpcpStringLength(WMSG_DIRECTORY_NAME),
|
|
Endpoint, (RpcpStringLength(Endpoint) + 1) * sizeof(RPC_CHAR));
|
|
|
|
RtlInitUnicodeString(&UnicodeString, LpcPortName);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString,
|
|
OBJ_CASE_INSENSITIVE, 0, SecurityDescriptor);
|
|
|
|
NtStatus = NtCreatePort(&LpcAddressPort, &ObjectAttributes,
|
|
sizeof(WMSG_BIND_EXCHANGE), PORT_MAXIMUM_MESSAGE_LENGTH, 0);
|
|
|
|
delete LpcPortName;
|
|
if ( NT_SUCCESS(NtStatus) )
|
|
{
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
delete *NetworkAddress;
|
|
*NetworkAddress = 0;
|
|
|
|
if ( NtStatus == STATUS_NO_MEMORY )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
if ( NtStatus == STATUS_INSUFFICIENT_RESOURCES )
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
if ( ( NtStatus == STATUS_OBJECT_PATH_INVALID )
|
|
|| ( NtStatus == STATUS_OBJECT_PATH_NOT_FOUND )
|
|
|| ( NtStatus == STATUS_OBJECT_NAME_INVALID )
|
|
|| ( NtStatus == STATUS_OBJECT_TYPE_MISMATCH ) )
|
|
{
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
|
|
#if DBG
|
|
|
|
if ( NtStatus != STATUS_OBJECT_NAME_COLLISION )
|
|
{
|
|
PrintToDebugger("RPC : NtCreatePort : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( NtStatus == STATUS_OBJECT_NAME_COLLISION );
|
|
return(RPC_S_DUPLICATE_ENDPOINT);
|
|
}
|
|
|
|
|
|
static RPC_CHAR HexDigits[] =
|
|
{
|
|
RPC_CONST_CHAR('0'),
|
|
RPC_CONST_CHAR('1'),
|
|
RPC_CONST_CHAR('2'),
|
|
RPC_CONST_CHAR('3'),
|
|
RPC_CONST_CHAR('4'),
|
|
RPC_CONST_CHAR('5'),
|
|
RPC_CONST_CHAR('6'),
|
|
RPC_CONST_CHAR('7'),
|
|
RPC_CONST_CHAR('8'),
|
|
RPC_CONST_CHAR('9'),
|
|
RPC_CONST_CHAR('A'),
|
|
RPC_CONST_CHAR('B'),
|
|
RPC_CONST_CHAR('C'),
|
|
RPC_CONST_CHAR('D'),
|
|
RPC_CONST_CHAR('E'),
|
|
RPC_CONST_CHAR('F')
|
|
};
|
|
|
|
|
|
static RPC_CHAR PAPI *
|
|
ULongToHexString (
|
|
IN RPC_CHAR PAPI * String,
|
|
IN unsigned long Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We convert an unsigned long into hex representation in the specified
|
|
string. The result is always eight characters long; zero padding is
|
|
done if necessary.
|
|
|
|
Arguments:
|
|
|
|
String - Supplies a buffer to put the hex representation into.
|
|
|
|
Number - Supplies the unsigned long to convert to hex.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the end of the hex string is returned.
|
|
|
|
--*/
|
|
{
|
|
*String++ = HexDigits[(Number >> 28) & 0x0F];
|
|
*String++ = HexDigits[(Number >> 24) & 0x0F];
|
|
*String++ = HexDigits[(Number >> 20) & 0x0F];
|
|
*String++ = HexDigits[(Number >> 16) & 0x0F];
|
|
*String++ = HexDigits[(Number >> 12) & 0x0F];
|
|
*String++ = HexDigits[(Number >> 8) & 0x0F];
|
|
*String++ = HexDigits[(Number >> 4) & 0x0F];
|
|
*String++ = HexDigits[Number & 0x0F];
|
|
return(String);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_ADDRESS::SetupAddressUnknownEndpoint (
|
|
OUT RPC_CHAR PAPI * PAPI * Endpoint,
|
|
OUT RPC_CHAR PAPI * PAPI * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN void PAPI * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence,
|
|
IN unsigned long EndpointFlags,
|
|
IN unsigned long NICFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is like WMSG_ADDRESS::SetupAddressWithEndpoint except we need to
|
|
make up the endpoint.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Returns the endpoint for this address. The ownership
|
|
of the buffer allocated to contain the endpoint passes to the
|
|
caller.
|
|
|
|
NetworkAddress - Returns the network address for this server. The
|
|
ownership of the buffer allocated to contain the network address
|
|
passes to the caller.
|
|
|
|
SecurityDescriptor - Optionally supplies a security descriptor to
|
|
be placed on this address.
|
|
|
|
PendingQueueSize - Passed to SetupWithKnownEndpoint().
|
|
|
|
RpcProtocolSequence - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully setup this address.
|
|
|
|
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
|
|
invalid.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|
setup the address.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to setup
|
|
the address.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
static unsigned int DynamicEndpointCount = 0;
|
|
RPC_CHAR DynamicEndpoint[64];
|
|
RPC_CHAR * String;
|
|
|
|
UNUSED(RpcProtocolSequence);
|
|
|
|
for (;;)
|
|
{
|
|
String = DynamicEndpoint;
|
|
|
|
*String++ = RPC_CONST_CHAR('W');
|
|
*String++ = RPC_CONST_CHAR('M');
|
|
*String++ = RPC_CONST_CHAR('S');
|
|
*String++ = RPC_CONST_CHAR('G');
|
|
|
|
String = ULongToHexString(String,
|
|
(unsigned long) NtCurrentTeb()->ClientId.UniqueProcess);
|
|
DynamicEndpointCount += 1;
|
|
*String++ = RPC_CONST_CHAR('.');
|
|
String = ULongToHexString(String, DynamicEndpointCount);
|
|
*String = 0;
|
|
|
|
RpcStatus = SetupAddressWithEndpoint(DynamicEndpoint,
|
|
lNetworkAddress, NumNetworkAddress, SecurityDescriptor,
|
|
PendingQueueSize, 0, EndpointFlags, NICFlags);
|
|
|
|
if ( RpcStatus != RPC_S_DUPLICATE_ENDPOINT )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
*Endpoint = DuplicateString(DynamicEndpoint);
|
|
if ( *Endpoint == 0 )
|
|
{
|
|
ASSERT( *lNetworkAddress != 0 );
|
|
delete *lNetworkAddress ;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
#if DBG
|
|
|
|
if ( ( RpcStatus != RPC_S_INVALID_SECURITY_DESC )
|
|
&& ( RpcStatus != RPC_S_OUT_OF_RESOURCES )
|
|
&& ( RpcStatus != RPC_S_OUT_OF_MEMORY ) )
|
|
{
|
|
PrintToDebugger("RPC : SetupAddressWithEndpoint : %d\n", RpcStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( ( RpcStatus == RPC_S_INVALID_SECURITY_DESC )
|
|
|| ( RpcStatus == RPC_S_OUT_OF_RESOURCES )
|
|
|| ( RpcStatus == RPC_S_OUT_OF_MEMORY ) );
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
inline WMSG_ASSOCIATION *
|
|
WMSG_ADDRESS::ReferenceAssociation (
|
|
IN unsigned long AssociationKey,
|
|
OUT int *AssociationType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given an assocation key, we need to map it into an association. The
|
|
association may already have been deleted, in which case, we need to
|
|
return zero.
|
|
|
|
Arguments:
|
|
|
|
AssociationKey - Supplies the key to be used to map into an association.
|
|
|
|
Return Value:
|
|
|
|
If the association still exists, it will be returned; otherwise, zero
|
|
will be returned.
|
|
|
|
--*/
|
|
{
|
|
WMSG_ASSOCIATION * Association;
|
|
unsigned short SequenceNumber;
|
|
unsigned short DictionaryKey;
|
|
|
|
SequenceNumber = (unsigned short) (AssociationKey & SEQUENCE_NUMBER_MASK);
|
|
DictionaryKey = (unsigned short) ((AssociationKey & DICTIONARY_KEY_MASK)
|
|
>> DICTIONARY_KEY_SHIFT) - 1;
|
|
RequestGlobalMutex();
|
|
Association = AssociationDictionary.Find(DictionaryKey);
|
|
if ( Association == 0 )
|
|
{
|
|
ClearGlobalMutex();
|
|
return(0);
|
|
}
|
|
|
|
*AssociationType = Association->AssociationType ;
|
|
|
|
if (*AssociationType == ASSOCIATION_TYPE_SERVER)
|
|
{
|
|
if ( ((WMSG_SASSOCIATION *) Association)->SequenceNumber
|
|
!= SequenceNumber )
|
|
{
|
|
ClearGlobalMutex();
|
|
return(0);
|
|
}
|
|
|
|
((WMSG_SASSOCIATION *) Association)->AssociationReferenceCount += 1;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(*AssociationType == ASSOCIATION_TYPE_CLIENT) ;
|
|
|
|
((WMSG_CASSOCIATION *) Association)->AssociationReferenceCount += 1 ;
|
|
}
|
|
|
|
ClearGlobalMutex();
|
|
|
|
return(Association);
|
|
}
|
|
|
|
|
|
inline void
|
|
WMSG_ADDRESS::DereferenceAssociation (
|
|
IN WMSG_SASSOCIATION * Association
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We are done using this address, so the reference count can be decremented.
|
|
If no one is referencing this association, then we can go ahead and
|
|
delete it.
|
|
|
|
Arguments:
|
|
|
|
Association - Supplies the association whose reference count should be
|
|
decremented.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
RequestGlobalMutex();
|
|
Association->AssociationReferenceCount -= 1;
|
|
if ( Association->AssociationReferenceCount == 0 )
|
|
{
|
|
AssociationDictionary.Delete(Association->DictionaryKey - 1);
|
|
AssociationCount--;
|
|
ClearGlobalMutex();
|
|
|
|
if (Association->LpcServerPort)
|
|
{
|
|
NtStatus = NtClose(Association->LpcServerPort);
|
|
|
|
#if DBG
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
|
|
}
|
|
#endif // DBG
|
|
ASSERT( NT_SUCCESS(NtStatus) );
|
|
}
|
|
|
|
if (Association->LpcClientPort)
|
|
{
|
|
NtStatus = NtClose(Association->LpcClientPort);
|
|
|
|
#if DBG
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
|
|
}
|
|
#endif // DBG
|
|
|
|
ASSERT( NT_SUCCESS(NtStatus) );
|
|
}
|
|
|
|
delete Association;
|
|
}
|
|
else
|
|
{
|
|
ClearGlobalMutex();
|
|
}
|
|
}
|
|
|
|
inline WMSG_MESSAGE *
|
|
WMSG_ADDRESS::DealWithLRPCRequest (
|
|
IN WMSG_MESSAGE * WMSGMessage,
|
|
IN WMSG_MESSAGE * WMSGReply,
|
|
IN BOOL Partial,
|
|
IN WMSG_ASSOCIATION *Association
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
WMSG_MESSAGE * WMSGReplyMessage ;
|
|
WMSG_SBINDING *SBinding = 0;
|
|
int Flags = WMSGMessage->Rpc.RpcHeader.Flags ;
|
|
NTSTATUS NtStatus ;
|
|
RPC_MESSAGE RpcMessage ;
|
|
RPC_RUNTIME_INFO RuntimeInfo ;
|
|
|
|
if (ServerListeningFlag == 0 &&
|
|
GlobalRpcServer->InqNumAutoListenInterfaces() == 0)
|
|
{
|
|
WMSGReplyMessage = WMSGMessage ;
|
|
SetFaultPacket(WMSGReplyMessage, RPC_S_SERVER_TOO_BUSY, 0, 0) ;
|
|
return WMSGReplyMessage;
|
|
}
|
|
|
|
AddressMutex.Request();
|
|
ActiveCallCount += 1;
|
|
|
|
if ( (ActiveCallCount - WMSGCallCount) >= CallThreadCount )
|
|
{
|
|
RpcStatus = Server->CreateThread(
|
|
(THREAD_PROC)&RecvLotsaCallsWrapper,
|
|
this
|
|
);
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
CallThreadCount += 1;
|
|
}
|
|
else
|
|
{
|
|
ActiveCallCount -= 1;
|
|
AddressMutex.Clear();
|
|
WMSGReplyMessage = WMSGMessage ;
|
|
SetFaultPacket(WMSGReplyMessage, RPC_S_SERVER_TOO_BUSY, 0, 0) ;
|
|
|
|
return WMSGReplyMessage;
|
|
}
|
|
}
|
|
|
|
AddressMutex.Clear();
|
|
|
|
|
|
RpcMessage.RpcFlags = 0;
|
|
RpcMessage.ReservedForRuntime = &RuntimeInfo ;
|
|
|
|
RpcStatus = ((WMSG_SASSOCIATION *) Association)->
|
|
WMSGMessageToRpcMessage(WMSGMessage, &RpcMessage);
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: WMSGMessageToRpcMessage failed: %d\n",
|
|
RpcStatus) ;
|
|
#endif
|
|
WMSGReplyMessage = WMSGMessage ;
|
|
SetFaultPacket(WMSGReplyMessage, WMSG_MSG_FAULT, 0, 0) ;
|
|
return WMSGReplyMessage;
|
|
}
|
|
|
|
WMSGReply->Rpc.RpcHeader.Flags = 0;
|
|
|
|
((WMSG_SASSOCIATION *) Association)->DealWithRequestMessage(
|
|
WMSGMessage, WMSGReply, &RpcMessage,
|
|
&SBinding,Flags, FALSE, TRUE) ;
|
|
|
|
WMSGReplyMessage = WMSGReply ;
|
|
WMSGReplyMessage->LpcHeader.u1.s1.TotalLength =
|
|
WMSGReplyMessage->LpcHeader.u1.s1.DataLength
|
|
+ sizeof(PORT_MESSAGE);
|
|
|
|
AutoListenCallCount.Decrement();
|
|
|
|
AddressMutex.Request();
|
|
ActiveCallCount -= 1;
|
|
|
|
if ((CallThreadCount - (ActiveCallCount - WMSGCallCount) <= 1 +
|
|
(fSpareThread != 0)) || (CallThreadCount <= MinimumCallThreads) )
|
|
{
|
|
AddressMutex.Clear();
|
|
if (SBinding)
|
|
{
|
|
SBinding->RpcInterface->EndAutoListenCall() ;
|
|
}
|
|
|
|
return WMSGReplyMessage;
|
|
}
|
|
|
|
// This thread is extraneous, reply and return this
|
|
// thread to the system.
|
|
|
|
CallThreadCount -= 1;
|
|
AddressMutex.Clear();
|
|
ASSERT( WMSGReplyMessage != 0 );
|
|
NtStatus = NtReplyPort(((WMSG_SASSOCIATION *) Association)->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGReplyMessage);
|
|
#if DBG
|
|
|
|
if ( ( !NT_SUCCESS(NtStatus) )
|
|
&& ( NtStatus != STATUS_INVALID_CID )
|
|
&& ( NtStatus != STATUS_REPLY_MESSAGE_MISMATCH )
|
|
&& ( NtStatus != STATUS_PORT_DISCONNECTED ) )
|
|
{
|
|
PrintToDebugger("RPC : NtReplyPort : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
ASSERT( ( NT_SUCCESS(NtStatus) )
|
|
|| ( NtStatus == STATUS_INVALID_CID )
|
|
|| ( NtStatus == STATUS_REPLY_MESSAGE_MISMATCH )
|
|
|| ( NtStatus == STATUS_PORT_DISCONNECTED ) );
|
|
|
|
MessageCache->FreeMessage(WMSGMessage) ;
|
|
if (SBinding)
|
|
{
|
|
SBinding->RpcInterface->EndAutoListenCall() ;
|
|
}
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
BOOL
|
|
WMSG_ADDRESS::DealWithWMSGRequest (
|
|
IN WMSG_MESSAGE *WMSGMessage,
|
|
IN WMSG_ENDPOINT **Endpoint,
|
|
IN HWND *hWndEndpoint,
|
|
IN WMSG_ASSOCIATION *Association,
|
|
OUT WMSG_MESSAGE **WMSGReplyMessage
|
|
)
|
|
{
|
|
MSGMEM *pMsgMem ;
|
|
THREAD_IDENTIFIER tid ;
|
|
RPC_STATUS RpcStatus;
|
|
int Flags = WMSGMessage->Rpc.RpcHeader.Flags ;
|
|
|
|
*WMSGReplyMessage = 0;
|
|
|
|
if (ServerListeningFlag == 0 &&
|
|
GlobalRpcServer->InqNumAutoListenInterfaces() == 0)
|
|
{
|
|
*WMSGReplyMessage = WMSGMessage;
|
|
SetFaultPacket(*WMSGReplyMessage,RPC_S_SERVER_TOO_BUSY,TRUE,Flags);
|
|
return 0;
|
|
}
|
|
|
|
pMsgMem = (MSGMEM *) WMSGMessage ;
|
|
pMsgMem->Info.Association = Association ;
|
|
pMsgMem->Info.RpcMessage.RpcFlags = 0;
|
|
|
|
RpcStatus = ((WMSG_SASSOCIATION *) Association)->
|
|
WMSGMessageToRpcMessage(WMSGMessage, &(pMsgMem->Info.RpcMessage)) ;
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: WMSGMessageToRpcMessage failed: %d\n",
|
|
RpcStatus) ;
|
|
#endif
|
|
*WMSGReplyMessage = WMSGMessage ;
|
|
SetFaultPacket(*WMSGReplyMessage, WMSG_MSG_FAULT, TRUE, Flags) ;
|
|
return 0;
|
|
}
|
|
|
|
if (WMSGMessage->Rpc.RpcHeader.ObjectUuidFlag)
|
|
{
|
|
tid = GlobalWMsgServer->OleGetTid(
|
|
&(WMSGMessage->Rpc.RpcHeader.ObjectUuid));
|
|
}
|
|
else
|
|
{
|
|
tid = 0;
|
|
}
|
|
|
|
if (tid == 0)
|
|
{
|
|
*Endpoint = 0 ;
|
|
}
|
|
else
|
|
{
|
|
GlobalWMsgServer->AcquireMutex() ;
|
|
|
|
*Endpoint = GlobalWMsgServer->GetEndpoint(tid) ;
|
|
if (*Endpoint == 0)
|
|
{
|
|
*WMSGReplyMessage = WMSGMessage;
|
|
SetFaultPacket(*WMSGReplyMessage,RPC_S_OBJECT_NOT_FOUND,
|
|
TRUE, Flags) ;
|
|
GlobalWMsgServer->ReleaseMutex() ;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
*hWndEndpoint = (*Endpoint)->InqhWnd() ;
|
|
if (*hWndEndpoint)
|
|
{
|
|
(*Endpoint)->BeginCall() ;
|
|
}
|
|
else
|
|
{
|
|
*WMSGReplyMessage = WMSGMessage;
|
|
SetFaultPacket(*WMSGReplyMessage,RPC_S_OBJECT_NOT_FOUND,
|
|
TRUE, Flags) ;
|
|
GlobalWMsgServer->ReleaseMutex() ;
|
|
return 0;
|
|
}
|
|
|
|
if (WMSGMessage->Rpc.RpcHeader.Flags & DISPATCH_INPUT_SYNC)
|
|
{
|
|
GlobalWMsgServer->ReleaseMutex() ;
|
|
}
|
|
}
|
|
}
|
|
|
|
pMsgMem->Info.Endpoint = *Endpoint ;
|
|
|
|
if ((WMSGMessage->Rpc.RpcHeader.Flags & DISPATCH_INPUT_SYNC) || (tid == 0))
|
|
{
|
|
AddressMutex.Request();
|
|
ActiveCallCount += 1;
|
|
|
|
RpcStatus = Server->CreateThread(
|
|
(THREAD_PROC)&RecvLotsaCallsWrapper,
|
|
this
|
|
);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ActiveCallCount -= 1;
|
|
AddressMutex.Clear();
|
|
*WMSGReplyMessage = WMSGMessage;
|
|
SetFaultPacket(*WMSGReplyMessage,RPC_S_SERVER_TOO_BUSY,
|
|
TRUE, Flags) ;
|
|
return 0 ;
|
|
}
|
|
else
|
|
{
|
|
CallThreadCount += 1;
|
|
}
|
|
|
|
AddressMutex.Clear();
|
|
|
|
if (tid == 0)
|
|
{
|
|
HandleRequest(WMSGMessage, (WMSG_SASSOCIATION *) Association,
|
|
(RPC_MESSAGE *) &(pMsgMem->Info.RpcMessage),
|
|
NULL, TRUE) ;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(*hWndEndpoint) ;
|
|
ASSERT(WMSGMessage->Rpc.RpcHeader.Flags & DISPATCH_INPUT_SYNC);
|
|
|
|
pMsgMem->Info.fSyncDispatch = TRUE ;
|
|
SetLastError(0) ;
|
|
GlobalWMsgServer->SendMessageW(*hWndEndpoint, WM_MSG_REQUEST,
|
|
(WPARAM) WMSG_MAGIC_VALUE, (LPARAM) pMsgMem) ;
|
|
|
|
if (GetLastError() != 0)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: SendMessage failed: %d\n", GetLastError()) ;
|
|
#endif
|
|
*WMSGReplyMessage = WMSGMessage;
|
|
SetFaultPacket(*WMSGReplyMessage,WMSG_MSG_FAULT, TRUE, Flags) ;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
AddressMutex.Request() ;
|
|
ActiveCallCount += 1 ;
|
|
WMSGCallCount += 1;
|
|
AddressMutex.Clear() ;
|
|
|
|
ASSERT(*hWndEndpoint) ;
|
|
|
|
pMsgMem->Info.fSyncDispatch = FALSE ;
|
|
if (GlobalWMsgServer->PostMessageW(*hWndEndpoint, WM_MSG_REQUEST,
|
|
(WPARAM) WMSG_MAGIC_VALUE, (LPARAM) pMsgMem) == FALSE)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: PostMessage Failed: %d\n", GetLastError()) ;
|
|
#endif
|
|
*WMSGReplyMessage = WMSGMessage;
|
|
SetFaultPacket(*WMSGReplyMessage,WMSG_MSG_FAULT, TRUE, Flags) ;
|
|
GlobalWMsgServer->ReleaseMutex() ;
|
|
return 0;
|
|
}
|
|
|
|
GlobalWMsgServer->ReleaseMutex() ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::ReceiveLotsaCalls (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Here is where we receive remote procedure calls to this address. One
|
|
more threads will be executing this routine at once.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
WMSG_ASSOCIATION * Association;
|
|
unsigned long AssociationKey;
|
|
char PaddedMessage[sizeof(WMSG_MESSAGE)+8] ;
|
|
WMSG_MESSAGE * Reply ;
|
|
WMSG_MESSAGE * WMSGMessage = 0;
|
|
WMSG_MESSAGE * WMSGReplyMessage = 0;
|
|
HWND hWndEndpoint ;
|
|
int AssociationType = 0;
|
|
int Flags = 0;
|
|
WMSG_ENDPOINT *Endpoint = 0;
|
|
BOOL PartialFlag ;
|
|
BOOL fContinue ;
|
|
|
|
Reply = (WMSG_MESSAGE *) Align8(PaddedMessage) ;
|
|
|
|
for (;;)
|
|
{
|
|
if (WMSGMessage == 0)
|
|
{
|
|
while ((WMSGMessage = MessageCache->AllocateMessage()) == 0)
|
|
{
|
|
Sleep(100) ;
|
|
}
|
|
}
|
|
|
|
ASSERT(WMSGReplyMessage == 0 ||
|
|
WMSGReplyMessage->Rpc.RpcHeader.MessageType < MAX_WMSG_MSG) ;
|
|
|
|
NtStatus = NtReplyWaitReceivePort(LpcAddressPort,
|
|
(PVOID *) &AssociationKey, (PORT_MESSAGE *) WMSGReplyMessage,
|
|
(PORT_MESSAGE *) WMSGMessage);
|
|
|
|
|
|
if ( NT_SUCCESS(NtStatus) )
|
|
{
|
|
if (WMSGMessage->LpcHeader.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
|
{
|
|
if (WMSGMessage->Connect.BindExchange.ConnectType
|
|
== WMSG_CONNECT_REQUEST)
|
|
{
|
|
DealWithNewClient(WMSGMessage) ;
|
|
}
|
|
else if (WMSGMessage->Connect.BindExchange.ConnectType
|
|
== WMSG_CONNECT_RESPONSE)
|
|
{
|
|
DealWithConnectResponse(WMSGMessage) ;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0) ;
|
|
}
|
|
WMSGReplyMessage = 0;
|
|
}
|
|
else
|
|
if ( WMSGMessage->LpcHeader.u2.s2.Type == LPC_CLIENT_DIED )
|
|
{
|
|
WMSGReplyMessage = 0;
|
|
}
|
|
else
|
|
if ( WMSGMessage->LpcHeader.u2.s2.Type == LPC_PORT_CLOSED )
|
|
{
|
|
Association = ReferenceAssociation(AssociationKey, &AssociationType);
|
|
if (Association == 0)
|
|
{
|
|
WMSGReplyMessage = 0;
|
|
continue;
|
|
}
|
|
|
|
if (AssociationType == ASSOCIATION_TYPE_SERVER)
|
|
{
|
|
((WMSG_SASSOCIATION *) Association)->DealWithCloseMessage();
|
|
WMSGReplyMessage = 0;
|
|
|
|
AddressMutex.Request();
|
|
int SpareThreads = CallThreadCount -
|
|
((ActiveCallCount -WMSGCallCount) + MinimumCallThreads);
|
|
|
|
if ( SpareThreads > 0 && (!fSpareThread
|
|
|| (AssociationCount < SpareThreads) ) )
|
|
{
|
|
CallThreadCount -= 1;
|
|
ASSERT(CallThreadCount > (ActiveCallCount - WMSGCallCount));
|
|
AddressMutex.Clear();
|
|
|
|
MessageCache->FreeMessage(WMSGMessage) ;
|
|
|
|
// Too many thread for too few connections,
|
|
// return this thread to the system.
|
|
return ;
|
|
}
|
|
AddressMutex.Clear();
|
|
}
|
|
else
|
|
{
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_CLIENT) ;
|
|
#if DBG
|
|
PrintToDebugger("WMSG: Server died\n") ;
|
|
#endif
|
|
((WMSG_CASSOCIATION *) Association)->AbortAssociation() ;
|
|
|
|
((WMSG_CASSOCIATION *) Association)->RemoveReference() ;
|
|
WMSGReplyMessage = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Association = ReferenceAssociation(AssociationKey, &AssociationType);
|
|
if ( Association == 0 )
|
|
{
|
|
WMSGReplyMessage = 0;
|
|
continue;
|
|
}
|
|
|
|
hWndEndpoint = 0 ;
|
|
Flags = WMSGMessage->Rpc.RpcHeader.Flags ;
|
|
PartialFlag = FALSE ;
|
|
fContinue = 1;
|
|
|
|
switch ( WMSGMessage->Bind.MessageType )
|
|
{
|
|
case WMSG_MSG_BIND :
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_SERVER) ;
|
|
((WMSG_SASSOCIATION *) Association)
|
|
->DealWithBindMessage(WMSGMessage);
|
|
|
|
WMSGReplyMessage = 0 ;
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
break;
|
|
|
|
case WMSG_MSG_COPY:
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_SERVER) ;
|
|
WMSGReplyMessage = ((WMSG_SASSOCIATION *) Association)
|
|
->DealWithCopyMessage(
|
|
(WMSG_COPY_MESSAGE *) WMSGMessage);
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
break;
|
|
|
|
case WMSG_MSG_BIND_BACK:
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_SERVER) ;
|
|
WMSGReplyMessage = ((WMSG_SASSOCIATION *) Association)
|
|
->DealWithBindBackMessage(WMSGMessage);
|
|
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
break;
|
|
|
|
case WMSG_PARTIAL_REQUEST:
|
|
case WMSG_PARTIAL_OUT:
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_SERVER) ;
|
|
WMSGReplyMessage = ((WMSG_SASSOCIATION *) Association)
|
|
->DealWithPipeRequest( WMSGMessage ) ;
|
|
|
|
if (WMSGReplyMessage == 0)
|
|
{
|
|
// the message will be free once we are done reading/writing
|
|
WMSGMessage = 0;
|
|
}
|
|
|
|
// we dereference the association after we read the partial data
|
|
break;
|
|
|
|
case WMSG_MSG_FAULT:
|
|
case WMSG_MSG_RESPONSE:
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_CLIENT) ;
|
|
if (((WMSG_CASSOCIATION *)Association)
|
|
->UnblockCConnection(WMSGMessage, LpcAddressPort) != RPC_S_OK)
|
|
{
|
|
ASSERT(0) ;
|
|
}
|
|
|
|
// the receive thread needs to allocate a new message
|
|
WMSGMessage = 0 ;
|
|
WMSGReplyMessage = 0;
|
|
|
|
((WMSG_CASSOCIATION *) Association)->RemoveReference() ;
|
|
break;
|
|
|
|
case WMSG_LRPC_REQUEST:
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_SERVER) ;
|
|
WMSGReplyMessage = DealWithLRPCRequest (
|
|
WMSGMessage, Reply, PartialFlag, Association) ;
|
|
|
|
if (WMSGReplyMessage == 0)
|
|
{
|
|
return;
|
|
}
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association) ;
|
|
break;
|
|
|
|
case WMSG_MSG_REQUEST :
|
|
ASSERT(AssociationType == ASSOCIATION_TYPE_SERVER) ;
|
|
if (DealWithWMSGRequest ( WMSGMessage, &Endpoint,
|
|
&hWndEndpoint, Association, &WMSGReplyMessage))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (WMSGReplyMessage == 0)
|
|
{
|
|
WMSGMessage = 0;
|
|
}
|
|
fContinue = 0;
|
|
break;
|
|
|
|
default:
|
|
#if DBG
|
|
PrintToDebugger("RPC : WMSG_ADDRESS::ReceiveLotsaCalls - Bad Message Type (%d) - %d\n",
|
|
WMSGMessage->Bind.MessageType, WMSGMessage->LpcHeader.u2.s2.Type);
|
|
#endif // DBG
|
|
|
|
ASSERT(0) ;
|
|
WMSGReplyMessage = 0 ;
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
break;
|
|
}
|
|
|
|
if (!fContinue)
|
|
{
|
|
if (WMSGReplyMessage != 0)
|
|
{
|
|
if (hWndEndpoint)
|
|
{
|
|
Endpoint->EndCall() ;
|
|
}
|
|
|
|
if (!(Flags & DISPATCH_ASYNC) &&
|
|
(Flags & WMSG_SYNC_CLIENT) == 0)
|
|
{
|
|
WMSGReplyMessage->Rpc.RpcHeader.ConnectionKey =
|
|
WMSGMessage->Rpc.RpcHeader.ConnectionKey ;
|
|
|
|
NtStatus = ((WMSG_SASSOCIATION *) Association)
|
|
->ReplyMessage(WMSGReplyMessage, Flags) ;
|
|
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("RPC: WMSG_ADDRESS: ReplyMessage failed\n") ;
|
|
#endif
|
|
|
|
((WMSG_SASSOCIATION *) Association)->AbortAssociation() ;
|
|
}
|
|
WMSGReplyMessage = 0 ;
|
|
}
|
|
DereferenceAssociation((WMSG_SASSOCIATION *) Association);
|
|
}
|
|
|
|
((WMSG_SASSOCIATION *) Association)->MaybeDereference() ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NtStatus == STATUS_PORT_DISCONNECTED
|
|
|| NtStatus == STATUS_INVALID_CID
|
|
|| NtStatus == STATUS_REPLY_MESSAGE_MISMATCH
|
|
)
|
|
{
|
|
WMSGReplyMessage = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( ( NtStatus != STATUS_NO_MEMORY )
|
|
&& ( NtStatus != STATUS_INSUFFICIENT_RESOURCES )
|
|
&& ( NtStatus != STATUS_UNSUCCESSFUL ) )
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("RPC : NtReplyWaitReceivePort : %lx\n", NtStatus);
|
|
#endif // DBG
|
|
ASSERT( ( NtStatus == STATUS_NO_MEMORY )
|
|
|| ( NtStatus == STATUS_INSUFFICIENT_RESOURCES )
|
|
|| ( NtStatus == STATUS_UNSUCCESSFUL ) );
|
|
WMSGReplyMessage = 0;
|
|
}
|
|
PauseExecution(500L);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define DEFAULT_PORT_DIR "\\RPC Control\\"
|
|
#define DEFAULT_PORT_NAME "ARPC Port1"
|
|
#define DEFAULT_REPLY_NAME "ARPC Reply Port"
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::DealWithNewClient (
|
|
IN WMSG_MESSAGE * ConnectionRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A new client has connected with our address port. We need to take
|
|
care of the new client and send a response.
|
|
|
|
Arguments:
|
|
|
|
ConnectionRequest - Supplies information need by LPC to abort the
|
|
connect request. Includes the bind request from the client.
|
|
This contains the information about which interface the client
|
|
wants to bind with. and which we use to send the status code
|
|
back in.
|
|
|
|
|
|
--*/
|
|
{
|
|
WMSG_SASSOCIATION * Association;
|
|
NTSTATUS NtStatus;
|
|
RPC_STATUS RpcStatus;
|
|
unsigned long AssociationKey;
|
|
|
|
Association = new WMSG_SASSOCIATION(this, &RpcStatus);
|
|
if ( Association == 0 )
|
|
{
|
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|
return;
|
|
}
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
delete Association ;
|
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|
return ;
|
|
}
|
|
|
|
RequestGlobalMutex();
|
|
Association->DictionaryKey = (unsigned short)
|
|
AssociationDictionary.Insert(Association) + 1;
|
|
AssociationCount++ ;
|
|
ClearGlobalMutex();
|
|
if ( Association->DictionaryKey == -1 )
|
|
{
|
|
RequestGlobalMutex();
|
|
AssociationCount-- ;
|
|
ClearGlobalMutex();
|
|
|
|
delete Association ;
|
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|
return;
|
|
}
|
|
|
|
ConnectionRequest->Connect.BindExchange.RpcStatus = RPC_S_OK;
|
|
|
|
ASSERT( sizeof(unsigned long) <= sizeof(PVOID) );
|
|
|
|
AssociationKey = (Association->DictionaryKey << DICTIONARY_KEY_SHIFT)
|
|
| Association->SequenceNumber;
|
|
NtStatus = NtAcceptConnectPort(&(Association->LpcServerPort),
|
|
(PVOID) AssociationKey, (PORT_MESSAGE *) ConnectionRequest,
|
|
TRUE, NULL, NULL);
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
Association->Delete() ;
|
|
#if DBG
|
|
PrintToDebugger("RPC : NtAcceptConnectPort : %lx\n", NtStatus);
|
|
#endif // DBG
|
|
return;
|
|
}
|
|
|
|
if (ConnectionRequest->Connect.BindExchange.fBindBack)
|
|
{
|
|
Association->BindBack(
|
|
(RPC_CHAR *)ConnectionRequest->Connect.BindExchange.szPortName,
|
|
(PVOID) ConnectionRequest->Connect.BindExchange.pAssoc) ;
|
|
}
|
|
|
|
NtStatus = NtCompleteConnectPort(Association->LpcServerPort);
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("RPC : NtCompleteConnectPort : %lx\n", NtStatus);
|
|
#endif // DBG
|
|
Association->Delete() ;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::DealWithConnectResponse (
|
|
IN WMSG_MESSAGE * ConnectResponse
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Just received a connect response from the remove server,
|
|
need to handle that.
|
|
|
|
Arguments:
|
|
|
|
ConnectionRequest -
|
|
Needed to get the pAssoc
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
HANDLE temp ;
|
|
WMSG_CASSOCIATION * Association ;
|
|
unsigned long AssociationKey;
|
|
|
|
Association = (WMSG_CASSOCIATION *)
|
|
ConnectResponse->Connect.BindExchange.pAssoc ;
|
|
|
|
ASSERT(Association != 0) ;
|
|
RequestGlobalMutex() ;
|
|
Association->DictionaryKey = (unsigned short)
|
|
AssociationDictionary.Insert(Association) + 1;
|
|
Association->SetAddress(this) ;
|
|
ClearGlobalMutex() ;
|
|
|
|
if (Association->DictionaryKey == -1)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: ConnResponse: Association->DictionaryKey == -1\n") ;
|
|
#endif
|
|
|
|
Association->RemoveReference(0) ;
|
|
return ;
|
|
}
|
|
|
|
AssociationKey = (Association->DictionaryKey << DICTIONARY_KEY_SHIFT) | 0;
|
|
|
|
NtStatus = NtAcceptConnectPort(&temp,
|
|
(PVOID) AssociationKey,
|
|
(PPORT_MESSAGE) ConnectResponse,
|
|
TRUE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: ConnResponse: NtAcceptConnectionPort failed: %lx\n",
|
|
NtStatus) ;
|
|
#endif
|
|
Association->RemoveReference() ;
|
|
return ;
|
|
}
|
|
|
|
Association->SetReceivePort(temp) ;
|
|
|
|
NtStatus = NtCompleteConnectPort(temp);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: ConnResponse: NtCompleteConnectPort failed: %lx\n",
|
|
NtStatus) ;
|
|
#endif
|
|
Association->RemoveReference() ;
|
|
return ;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_ADDRESS::RejectNewClient (
|
|
IN WMSG_MESSAGE * ConnectionRequest,
|
|
IN RPC_STATUS RpcStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A new client has connected with our address port. We need to reject
|
|
the client.
|
|
|
|
Arguments:
|
|
|
|
ConnectionRequest - Supplies information need by LPC to abort the
|
|
connect request. Includes the bind request from the client,
|
|
which we use to send the status code back in.
|
|
|
|
|
|
RpcStatus - Supplies the reason the client is being rejected.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
HANDLE Ignore;
|
|
|
|
ASSERT(RpcStatus != RPC_S_OK);
|
|
|
|
ConnectionRequest->Connect.BindExchange.RpcStatus = RpcStatus;
|
|
NtStatus = NtAcceptConnectPort(&Ignore, NULL, (PORT_MESSAGE *) ConnectionRequest, FALSE,
|
|
NULL, NULL);
|
|
#if DBG
|
|
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
PrintToDebugger("RPC : NtAcceptConnectPort : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( NT_SUCCESS(NtStatus) );
|
|
}
|
|
|
|
|
|
WMSG_SASSOCIATION::WMSG_SASSOCIATION (
|
|
IN WMSG_ADDRESS * Address,
|
|
IN RPC_STATUS *RpcStatus
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
static unsigned short SequenceNumber = 1;
|
|
|
|
*RpcStatus = RPC_S_OK ;
|
|
LpcServerPort = 0;
|
|
LpcClientPort = 0 ;
|
|
this->Address = Address;
|
|
AssociationReferenceCount = 1;
|
|
Aborted = 0 ;
|
|
Deleted = -1 ;
|
|
TokenHandle = 0;
|
|
OpenThreadTokenFailed = 0;
|
|
|
|
UserName = NULL;
|
|
|
|
RequestGlobalMutex();
|
|
this->SequenceNumber = SequenceNumber;
|
|
SequenceNumber += 1;
|
|
ClearGlobalMutex();
|
|
AssociationType = ASSOCIATION_TYPE_SERVER ;
|
|
}
|
|
|
|
|
|
WMSG_SASSOCIATION::~WMSG_SASSOCIATION (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will call this routine when the client has notified us that this port
|
|
has closed, and there are no calls outstanding on it.
|
|
|
|
--*/
|
|
{
|
|
PVOID Buffer;
|
|
WMSG_SBINDING * Binding;
|
|
|
|
if (UserName)
|
|
{
|
|
RpcpFarFree(UserName) ;
|
|
}
|
|
|
|
GlobalMutexRequest();
|
|
|
|
Bindings.Reset();
|
|
while ( (Binding = Bindings.Next()) != 0 )
|
|
{
|
|
delete Binding;
|
|
}
|
|
|
|
GlobalMutexClear();
|
|
|
|
if (TokenHandle)
|
|
{
|
|
CloseHandle(TokenHandle) ;
|
|
}
|
|
}
|
|
|
|
void
|
|
WMSG_SASSOCIATION::Delete(
|
|
)
|
|
{
|
|
WMSG_SCALL *SCall ;
|
|
|
|
if (InterlockedIncrement(&Deleted) == 0)
|
|
{
|
|
RequestGlobalMutex() ;
|
|
SCallDict.Reset() ;
|
|
while ((SCall = SCallDict.Next()) != 0)
|
|
{
|
|
SCall->Deleted = 1;
|
|
if (SCall->PipeEvent)
|
|
{
|
|
SetEvent(SCall->PipeEvent) ;
|
|
}
|
|
}
|
|
ClearGlobalMutex() ;
|
|
|
|
Address->DereferenceAssociation(this);
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SASSOCIATION::BindBack (
|
|
RPC_CHAR *Endpoint,
|
|
PVOID pAssoc
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|
RPC_CHAR * LpcPortName ;
|
|
UNICODE_STRING unicodePortName;
|
|
WMSG_BIND_EXCHANGE BindExchange;
|
|
unsigned long BindExchangeLength = sizeof(WMSG_BIND_EXCHANGE);
|
|
|
|
LpcPortName = new RPC_CHAR[RpcpStringLength(Endpoint)
|
|
+ RpcpStringLength(WMSG_DIRECTORY_NAME) + 1];
|
|
|
|
if ( LpcPortName == 0 )
|
|
{
|
|
Delete() ;
|
|
#if DBG
|
|
PrintToDebugger("WMSG: Out of memory in DealWithNewClient\n") ;
|
|
#endif
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
RpcpMemoryCopy(LpcPortName, WMSG_DIRECTORY_NAME,
|
|
RpcpStringLength(WMSG_DIRECTORY_NAME) * sizeof(RPC_CHAR));
|
|
RpcpMemoryCopy(LpcPortName + RpcpStringLength(WMSG_DIRECTORY_NAME),
|
|
Endpoint, (RpcpStringLength(Endpoint) + 1) * sizeof(RPC_CHAR));
|
|
|
|
RtlInitUnicodeString(&unicodePortName, LpcPortName);
|
|
|
|
// Hack Hack, where do I get the real QOS values from ??
|
|
SecurityQualityOfService.EffectiveOnly = TRUE;
|
|
SecurityQualityOfService.ContextTrackingMode =
|
|
SECURITY_DYNAMIC_TRACKING;
|
|
SecurityQualityOfService.ImpersonationLevel = SecurityIdentification;
|
|
|
|
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
|
|
|
|
BindExchange.ConnectType = WMSG_CONNECT_RESPONSE ;
|
|
BindExchange.pAssoc = pAssoc ;
|
|
|
|
NtStatus = NtConnectPort(&LpcClientPort,
|
|
&unicodePortName, &SecurityQualityOfService, 0, 0, 0,
|
|
&BindExchange, &BindExchangeLength);
|
|
|
|
delete LpcPortName ;
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: NtConnectPort : %lx\n", NtStatus);
|
|
#endif // DBG
|
|
Delete() ;
|
|
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
|
|
WMSG_MESSAGE *
|
|
WMSG_SASSOCIATION::DealWithBindBackMessage (
|
|
IN WMSG_MESSAGE *BindBackMessage
|
|
)
|
|
{
|
|
RPC_STATUS Status ;
|
|
|
|
Status = BindBack((RPC_CHAR *) BindBackMessage->BindBack.szPortName,
|
|
(PVOID) BindBackMessage->BindBack.pAssoc) ;
|
|
|
|
BindBackMessage->Ack.MessageType = WMSG_MSG_ACK ;
|
|
BindBackMessage->Ack.RpcStatus = Status ;
|
|
BindBackMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_BIND_MESSAGE) - sizeof(PORT_MESSAGE);
|
|
|
|
return BindBackMessage ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SASSOCIATION::AddBinding (
|
|
IN OUT WMSG_BIND_EXCHANGE * BindExchange
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will attempt to add a new binding to this association.
|
|
|
|
Arguments:
|
|
|
|
BindExchange - Supplies a description of the interface to which the
|
|
client wish to bind.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
RPC_SYNTAX_IDENTIFIER TransferSyntax;
|
|
RPC_INTERFACE * RpcInterface;
|
|
WMSG_SBINDING * Binding;
|
|
|
|
RpcStatus = Address->FindInterfaceTransfer(&(BindExchange->InterfaceId),
|
|
&(BindExchange->TransferSyntax), 1, &TransferSyntax, &RpcInterface);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
return(RpcStatus);
|
|
}
|
|
|
|
Binding = new WMSG_SBINDING(RpcInterface, &(BindExchange->TransferSyntax));
|
|
if ( Binding == 0 )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
Binding->PresentationContext = Bindings.Insert(Binding);
|
|
if ( Binding->PresentationContext == -1 )
|
|
{
|
|
delete Binding;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
BindExchange->PresentationContext = Binding->PresentationContext;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SASSOCIATION::SaveToken (
|
|
IN WMSG_MESSAGE *WMSGMessage
|
|
)
|
|
{
|
|
NTSTATUS NtStatus ;
|
|
HANDLE ImpersonationToken = 0;
|
|
|
|
NtStatus = NtImpersonateClientOfPort(LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGMessage);
|
|
|
|
if (NT_ERROR(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: NtImpersonateClientOfPort failed: 0x%lX\n", NtStatus) ;
|
|
#endif
|
|
return RPC_S_INVALID_AUTH_IDENTITY ;
|
|
}
|
|
|
|
if (TokenHandle)
|
|
{
|
|
CloseHandle(TokenHandle) ;
|
|
}
|
|
|
|
if (OpenThreadToken (GetCurrentThread(),
|
|
TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|
FALSE, &TokenHandle) == FALSE)
|
|
{
|
|
TokenHandle = 0;
|
|
OpenThreadTokenFailed = 1;
|
|
#if DBG
|
|
PrintToDebugger("WMSG: OpenThreadToken failed\n") ;
|
|
#endif
|
|
}
|
|
|
|
NtStatus = NtSetInformationThread(NtCurrentThread(),
|
|
ThreadImpersonationToken, &ImpersonationToken, sizeof(HANDLE));
|
|
|
|
#if DBG
|
|
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( NT_SUCCESS(NtStatus) );
|
|
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_SASSOCIATION::DealWithBindMessage (
|
|
IN WMSG_MESSAGE * WMSGMessage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
WMSG_ADDRESS::ReceiveLotsaCalls will call this routine when the client
|
|
sends a bind message. We need to process the bind message, and send
|
|
a response to the client.
|
|
|
|
Arguments:
|
|
|
|
WMSGMessage - Supplies the bind message. We will also use this to send
|
|
the response.
|
|
|
|
Return Value:
|
|
|
|
The reply message to be sent to the client will be returned.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus ;
|
|
NTSTATUS NtStatus ;
|
|
|
|
RpcStatus = SaveToken(WMSGMessage) ;
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
WMSGMessage->Bind.BindExchange.RpcStatus = RpcStatus ;
|
|
}
|
|
else
|
|
{
|
|
WMSGMessage->Bind.BindExchange.RpcStatus = AddBinding(
|
|
&(WMSGMessage->Bind.BindExchange));
|
|
}
|
|
|
|
WMSGMessage->LpcHeader.u1.s1.DataLength = sizeof(WMSG_BIND_MESSAGE)
|
|
- sizeof(PORT_MESSAGE);
|
|
WMSGMessage->Bind.MessageType = WMSG_BIND_ACK ;
|
|
|
|
NtStatus = NtReplyPort(LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGMessage) ;
|
|
|
|
if (NT_ERROR(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: NtReplyPort failed: %lX\n", NtStatus) ;
|
|
#endif
|
|
Delete() ;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_SASSOCIATION::DealWithRequestMessage (
|
|
IN WMSG_MESSAGE * WMSGMessage,
|
|
IN OUT WMSG_MESSAGE *WMSGReply,
|
|
IN PRPC_MESSAGE RpcMessage,
|
|
IN WMSG_SBINDING **SBinding,
|
|
IN unsigned int Flags,
|
|
IN BOOL IsWMsg,
|
|
IN BOOL fSyncClient
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will process the original request message in this routine, dispatch
|
|
the remote procedure call to the stub, and then send the response
|
|
message.
|
|
|
|
Arguments:
|
|
|
|
WMSGMessage - Supplies the request message which was received from
|
|
the client.
|
|
|
|
WMSGReplyMessage - The message to be sent to the client.
|
|
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
WMSG_SCALL SCall(this, WMSGMessage, WMSGReply, Flags, fSyncClient);
|
|
RPC_STATUS RpcStatus, ExceptionCode;
|
|
|
|
*SBinding = Bindings.Find(WMSGMessage->Rpc.RpcHeader.PresentationContext);
|
|
if ( *SBinding == 0 )
|
|
{
|
|
WMSGReply->LpcHeader.ClientId =
|
|
WMSGMessage->LpcHeader.ClientId;
|
|
WMSGReply->LpcHeader.MessageId =
|
|
WMSGMessage->LpcHeader.MessageId;
|
|
WMSGReply->LpcHeader.CallbackId =
|
|
WMSGMessage->LpcHeader.CallbackId;
|
|
WMSGReply->LpcHeader.u2.s2.DataInfoOffset =
|
|
WMSGMessage->LpcHeader.u2.s2.DataInfoOffset;
|
|
|
|
SetFaultPacket(WMSGReply, RPC_S_UNKNOWN_IF, IsWMsg, Flags) ;
|
|
return ;
|
|
}
|
|
|
|
(*SBinding)->RpcInterface->BeginAutoListenCall() ;
|
|
Address->BeginAutoListenCall() ;
|
|
|
|
SCall.SBinding = *SBinding;
|
|
|
|
RpcMessage->TransferSyntax = &((*SBinding)->TransferSyntax);
|
|
RpcMessage->ProcNum = WMSGMessage->Rpc.RpcHeader.ProcedureNumber;
|
|
RpcMessage->Handle = &SCall;
|
|
|
|
// NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
|
|
|
|
RpcMessage->DataRepresentation = 0x00 | 0x10 | 0x0000;
|
|
|
|
if ( WMSGMessage->Rpc.RpcHeader.ObjectUuidFlag != 0 )
|
|
{
|
|
SCall.ObjectUuidFlag = 1;
|
|
RpcpMemoryCopy(&(SCall.ObjectUuid),
|
|
&(WMSGMessage->Rpc.RpcHeader.ObjectUuid), sizeof(UUID));
|
|
}
|
|
|
|
SCall.ClientId = WMSGMessage->LpcHeader.ClientId;
|
|
SCall.MessageId = WMSGMessage->LpcHeader.MessageId;
|
|
SCall.CallbackId = WMSGMessage->LpcHeader.CallbackId;
|
|
SCall.DataInfoOffset = WMSGMessage->LpcHeader.u2.s2.DataInfoOffset;
|
|
|
|
RpcpSetThreadContext(&SCall);
|
|
|
|
//
|
|
// Check IF Level Security
|
|
//
|
|
if ((*SBinding)->RpcInterface->IsSecurityCallbackReqd() != 0)
|
|
{
|
|
if ((*SBinding)->CheckSecurity(&SCall) != RPC_S_OK)
|
|
{
|
|
WMSGReply->LpcHeader.ClientId =
|
|
WMSGMessage->LpcHeader.ClientId;
|
|
WMSGReply->LpcHeader.MessageId =
|
|
WMSGMessage->LpcHeader.MessageId;
|
|
WMSGReply->LpcHeader.CallbackId =
|
|
WMSGMessage->LpcHeader.CallbackId;
|
|
WMSGReply->LpcHeader.u2.s2.DataInfoOffset =
|
|
WMSGMessage->LpcHeader.u2.s2.DataInfoOffset;
|
|
|
|
SetFaultPacket(WMSGReply, RPC_S_ACCESS_DENIED, IsWMsg, Flags) ;
|
|
|
|
RpcpSetThreadContext(0) ;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( SCall.ObjectUuidFlag != 0 )
|
|
{
|
|
RpcStatus = (*SBinding)->RpcInterface->DispatchToStubWithObject(
|
|
RpcMessage, &(SCall.ObjectUuid), 0, &ExceptionCode);
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = (*SBinding)->RpcInterface->DispatchToStub(RpcMessage, 0,
|
|
&ExceptionCode);
|
|
}
|
|
RpcpSetThreadContext(0);
|
|
|
|
SCall.RevertToSelf();
|
|
|
|
if (!IsWMsg)
|
|
{
|
|
if (SCall.ConnectionKey)
|
|
{
|
|
SCall.DealWithPipeReply() ;
|
|
}
|
|
|
|
WMSGReply->LpcHeader.ClientId = SCall.ClientId ;
|
|
WMSGReply->LpcHeader.MessageId = SCall.MessageId ;
|
|
WMSGReply->LpcHeader.CallbackId = SCall.CallbackId;
|
|
WMSGReply->LpcHeader.u2.s2.DataInfoOffset = SCall.DataInfoOffset;
|
|
}
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( RpcStatus == RPC_P_EXCEPTION_OCCURED )
|
|
{
|
|
SetFaultPacket(WMSGReply, WMSGMapRpcStatus(ExceptionCode),
|
|
IsWMsg, Flags) ;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( ( RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
|
|
|| ( RpcStatus == RPC_S_UNKNOWN_IF )
|
|
|| ( RpcStatus == RPC_S_NOT_LISTENING )
|
|
|| ( RpcStatus == RPC_S_SERVER_TOO_BUSY )
|
|
|| ( RpcStatus == RPC_S_UNSUPPORTED_TYPE ) );
|
|
|
|
if ( RpcStatus == RPC_S_NOT_LISTENING )
|
|
{
|
|
RpcStatus = RPC_S_SERVER_TOO_BUSY;
|
|
}
|
|
|
|
SetFaultPacket(WMSGReply, WMSGMapRpcStatus(RpcStatus),
|
|
IsWMsg, Flags) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The rest of the response headers are set in ::GetBuffer.
|
|
WMSGReply->Rpc.RpcHeader.MessageType = WMSG_MSG_RESPONSE;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
WMSG_SASSOCIATION::ReplyMessage(
|
|
IN WMSG_MESSAGE * WMSGMessage,
|
|
IN int Flags
|
|
)
|
|
{
|
|
NTSTATUS NtStatus ;
|
|
WMSG_MESSAGE ReplyMessage ;
|
|
|
|
ASSERT( WMSGMessage != 0 );
|
|
WMSGMessage->LpcHeader.u1.s1.TotalLength =
|
|
WMSGMessage->LpcHeader.u1.s1.DataLength + sizeof(PORT_MESSAGE);
|
|
|
|
if ((WMSGMessage->Rpc.RpcHeader.MessageType == WMSG_MSG_RESPONSE) &&
|
|
(WMSGMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_SERVER))
|
|
{
|
|
if (Flags & WMSG_SYNC_CLIENT)
|
|
{
|
|
NtStatus = NtReplyPort(LpcServerPort, (PORT_MESSAGE *) WMSGMessage) ;
|
|
}
|
|
else
|
|
{
|
|
NtStatus = NtRequestWaitReplyPort(LpcClientPort,
|
|
(PORT_MESSAGE *) WMSGMessage,
|
|
(PORT_MESSAGE *) &ReplyMessage) ;
|
|
RpcpFarFree(WMSGMessage->Rpc.Request.DataEntries[0].Base);
|
|
}
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx, ASSOC: 0x%x, Port: 0x%x\n",
|
|
NtStatus, this, LpcClientPort);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ASSERT((Flags & WMSG_SYNC_CLIENT) ||
|
|
(ReplyMessage.Ack.MessageType == WMSG_MSG_ACK)) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Flags & WMSG_SYNC_CLIENT)
|
|
{
|
|
NtStatus = NtReplyPort(LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGMessage);
|
|
}
|
|
else
|
|
{
|
|
WMSGMessage->LpcHeader.CallbackId = 0;
|
|
WMSGMessage->LpcHeader.MessageId = 0;
|
|
NtStatus = NtRequestPort(LpcClientPort,
|
|
(PORT_MESSAGE *) WMSGMessage);
|
|
}
|
|
#if DBG
|
|
|
|
if ( ( !NT_SUCCESS(NtStatus) )
|
|
&& ( NtStatus != STATUS_INVALID_CID )
|
|
&& ( NtStatus != STATUS_REPLY_MESSAGE_MISMATCH )
|
|
&& ( NtStatus != STATUS_PORT_DISCONNECTED ) )
|
|
{
|
|
PrintToDebugger("RPC : NtRequestPort : %lx, ASSOC: 0x%x, Port: 0x%x\n",
|
|
NtStatus, this, LpcClientPort);
|
|
}
|
|
|
|
#endif // DBG
|
|
ASSERT( ( NT_SUCCESS(NtStatus) )
|
|
|| ( NtStatus == STATUS_INVALID_CID )
|
|
|| ( NtStatus == STATUS_REPLY_MESSAGE_MISMATCH )
|
|
|| ( NtStatus == STATUS_PORT_DISCONNECTED ) );
|
|
}
|
|
|
|
return NtStatus ;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
WMSG_SASSOCIATION::DealWithCloseMessage (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The client has closed this association. We need to deal with that
|
|
fact.
|
|
|
|
--*/
|
|
{
|
|
// We need to dereference the association twice: once for the call to
|
|
// ReferenceAssociation and once for the implicit reference from the
|
|
// client. If you look at the constructor for WMSG_SASSOCIATION you
|
|
// will see that the reference count is initialized to one.
|
|
Delete() ;
|
|
Address->DereferenceAssociation(this);
|
|
}
|
|
|
|
|
|
WMSG_MESSAGE *
|
|
WMSG_SASSOCIATION::DealWithCopyMessage (
|
|
IN WMSG_COPY_MESSAGE * WMSGMessage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will process a copy message in this routine; this means that we need
|
|
to copy a buffer of data from the server into the client's address
|
|
space.
|
|
|
|
Arguments:
|
|
|
|
WMSGMessage - Supplies the copy message which was received from
|
|
the client.
|
|
|
|
Return Value:
|
|
|
|
The reply message to be sent to the client will be returned.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
unsigned long NumberOfBytesWritten;
|
|
PVOID Buffer;
|
|
|
|
GlobalMutexRequest();
|
|
Buffer = Buffers.Find(WMSGMessage->Server.Buffer);
|
|
if ( WMSGMessage->IsPartial == 0 && Buffer != 0 )
|
|
{
|
|
Buffers.Delete(WMSGMessage->Server.Buffer);
|
|
}
|
|
GlobalMutexClear();
|
|
if ( WMSGMessage->RpcStatus == RPC_S_OK )
|
|
{
|
|
if ( Buffer == 0 )
|
|
{
|
|
WMSGMessage->RpcStatus = RPC_S_PROTOCOL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
NtStatus = NtWriteRequestData(LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGMessage, 0, (PVOID) Buffer,
|
|
WMSGMessage->Server.Length, &NumberOfBytesWritten);
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
WMSGMessage->RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( WMSGMessage->Server.Length==NumberOfBytesWritten );
|
|
WMSGMessage->RpcStatus = RPC_S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
WMSGMessage->LpcHeader.u1.s1.DataLength = sizeof(WMSG_COPY_MESSAGE)
|
|
- sizeof(PORT_MESSAGE);
|
|
|
|
if ( WMSGMessage->IsPartial == 0 && Buffer != 0 )
|
|
{
|
|
RpcpFarFree(Buffer);
|
|
}
|
|
|
|
return((WMSG_MESSAGE *) WMSGMessage);
|
|
}
|
|
|
|
|
|
WMSG_MESSAGE *
|
|
WMSG_SASSOCIATION::DealWithPipeRequest (
|
|
IN WMSG_MESSAGE *WMSGMessage
|
|
)
|
|
{
|
|
WMSG_SCALL *SCall ;
|
|
|
|
RequestGlobalMutex() ;
|
|
SCall = SCallDict.Find(WMSGMessage->Rpc.RpcHeader.ConnectionKey-1) ;
|
|
ClearGlobalMutex() ;
|
|
|
|
if (SCall == 0)
|
|
{
|
|
SetFaultPacket(WMSGMessage, RPC_S_SERVER_TOO_BUSY, 0, 0) ;
|
|
return WMSGMessage;
|
|
}
|
|
|
|
SCall->DealWithPipeRequest(WMSGMessage) ;
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_SCALL::DealWithPipeReply (
|
|
)
|
|
{
|
|
if (PipeSendCalled && !Deleted)
|
|
{
|
|
if ((WaitForSingleObject(PipeEvent, INFINITE) == WAIT_FAILED) || Deleted)
|
|
return ;
|
|
}
|
|
|
|
if (PipeMessage)
|
|
{
|
|
MessageId = PipeMessage->LpcHeader.MessageId ;
|
|
ClientId = PipeMessage->LpcHeader.ClientId ;
|
|
CallbackId = PipeMessage->LpcHeader.CallbackId ;
|
|
DataInfoOffset = PipeMessage->LpcHeader.u2.s2.DataInfoOffset ;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_SCALL::DealWithPipeRequest (
|
|
IN WMSG_MESSAGE *WMSGMessage
|
|
)
|
|
{
|
|
PipeMessage = WMSGMessage ;
|
|
SetEvent(PipeEvent) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::SetupForPipes(
|
|
)
|
|
{
|
|
if (PipeEvent == 0)
|
|
{
|
|
PipeEvent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
|
|
if (PipeEvent == 0)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
GlobalMutexRequest();
|
|
ConnectionKey = Association->SCallDict.Insert(this) ;
|
|
if (ConnectionKey == -1)
|
|
{
|
|
GlobalMutexClear() ;
|
|
CloseHandle(PipeEvent) ;
|
|
PipeEvent = 0;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
ConnectionKey++ ;
|
|
GlobalMutexClear() ;
|
|
}
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::SendAck (
|
|
IN WMSG_MESSAGE *AckMessage,
|
|
BOOL fPipeMessage,
|
|
IN int ValidDataSize,
|
|
IN int Flags,
|
|
IN RPC_STATUS Status
|
|
)
|
|
{
|
|
NTSTATUS NtStatus ;
|
|
|
|
if (fPipeMessage)
|
|
{
|
|
PipeMessage = 0;
|
|
|
|
// think before you remove this...
|
|
ResetEvent(PipeEvent) ;
|
|
}
|
|
|
|
AckMessage->Ack.MessageType = WMSG_MSG_ACK ;
|
|
AckMessage->Ack.ValidDataSize = ValidDataSize ;
|
|
AckMessage->Ack.Flags = Flags;
|
|
AckMessage->Ack.ConnectionKey = ConnectionKey ;
|
|
AckMessage->Ack.RpcStatus = Status ;
|
|
AckMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_ACK_MESSAGE) - sizeof(PORT_MESSAGE) ;
|
|
AckMessage->LpcHeader.u1.s1.TotalLength = sizeof(WMSG_ACK_MESSAGE) ;
|
|
|
|
// setup the reply message
|
|
NtStatus = NtReplyPort(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) AckMessage) ;
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: NtReplyPort failed, 0x%lx\n", NtStatus) ;
|
|
#endif
|
|
if (fPipeMessage)
|
|
{
|
|
MessageCache->FreeMessage(AckMessage) ;
|
|
}
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
if (fPipeMessage)
|
|
{
|
|
MessageCache->FreeMessage(AckMessage) ;
|
|
}
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::ReadData (
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN int Extra
|
|
)
|
|
{
|
|
char *Buffer ;
|
|
int Length ;
|
|
RPC_STATUS RpcStatus ;
|
|
unsigned long NumberOfBytesRead ;
|
|
NTSTATUS NtStatus ;
|
|
|
|
if ((WaitForSingleObject(PipeEvent, INFINITE) == WAIT_FAILED) || Deleted)
|
|
{
|
|
return RPC_S_CALL_FAILED;
|
|
}
|
|
|
|
ASSERT(PipeMessage) ;
|
|
|
|
Length = PipeMessage->Rpc.Request.DataEntries[0].Size;
|
|
|
|
if (Extra)
|
|
{
|
|
int OldLength ;
|
|
|
|
OldLength = Message->BufferLength ;
|
|
RpcStatus = GetBufferDo(Message, OldLength+Length, 1) ;
|
|
Buffer = (char *) Message->Buffer + OldLength ;
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = GetBufferDo(Message, Length, 0) ;
|
|
Buffer = (char *) Message->Buffer ;
|
|
}
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
Association->Address->DereferenceAssociation(Association) ;
|
|
return RpcStatus ;
|
|
}
|
|
|
|
NtStatus = NtReadRequestData(Association->LpcServerPort,
|
|
(PORT_MESSAGE*) PipeMessage, 0, Buffer,
|
|
Length, &NumberOfBytesRead) ;
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: NtReadRequestData failed\n") ;
|
|
#endif
|
|
Association->Address->DereferenceAssociation(Association) ;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
ASSERT( Length == NumberOfBytesRead );
|
|
|
|
if ((PipeMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_PARTIAL) == 0)
|
|
{
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SendAck(PipeMessage) ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
RpcpFarFree(Message->Buffer);
|
|
}
|
|
}
|
|
|
|
Association->Address->DereferenceAssociation(Association) ;
|
|
return RpcStatus ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::WriteData (
|
|
IN void *Buffer,
|
|
IN int BufferLength,
|
|
IN OUT int *LengthWritten
|
|
)
|
|
{
|
|
NTSTATUS NtStatus ;
|
|
unsigned long NumberOfBytesWritten ;
|
|
RPC_STATUS RpcStatus ;
|
|
|
|
if ((WaitForSingleObject(PipeEvent, INFINITE) == WAIT_FAILED) || Deleted)
|
|
{
|
|
return RPC_S_CALL_FAILED ;
|
|
}
|
|
|
|
ASSERT(PipeMessage) ;
|
|
|
|
*LengthWritten = (PipeMessage->Rpc.Request.DataEntries[0].Size > BufferLength)
|
|
? BufferLength:PipeMessage->Rpc.Request.DataEntries[0].Size ;
|
|
|
|
NtStatus = NtWriteRequestData(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) PipeMessage, 0, (PVOID) Buffer,
|
|
*LengthWritten, &NumberOfBytesWritten);
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( *LengthWritten==NumberOfBytesWritten );
|
|
RpcStatus = RPC_S_OK;
|
|
}
|
|
|
|
RpcStatus = SendAck(PipeMessage, 1, *LengthWritten, 0, RpcStatus) ;
|
|
|
|
Association->Address->DereferenceAssociation(Association) ;
|
|
return RpcStatus ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::GetBuffer (
|
|
IN OUT PRPC_MESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will allocate a buffer which will be used to either send a request
|
|
or receive a response.
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the length of the buffer that is needed. The buffer
|
|
will be returned.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - A buffer has been successfully allocated. It will be of at
|
|
least the required length.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate that
|
|
large a buffer.
|
|
|
|
--*/
|
|
{
|
|
int BufferKey ;
|
|
|
|
ASSERT(WMSGReplyMessage != 0) ;
|
|
|
|
if (Message->RpcFlags & RPC_BUFFER_PARTIAL)
|
|
{
|
|
CurrentBufferLength = (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
|
|
? MINIMUM_PARTIAL_BUFFLEN:Message->BufferLength ;
|
|
|
|
Message->Buffer = RpcpFarAllocate(CurrentBufferLength) ;
|
|
if (Message->Buffer == 0)
|
|
{
|
|
CurrentBufferLength = 0;
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
}
|
|
else if ( Message->BufferLength <= MAXIMUM_MESSAGE_BUFFER )
|
|
{
|
|
ASSERT( ((unsigned long) WMSGReplyMessage->Rpc.Buffer) % 8 == 0 );
|
|
Message->Buffer = WMSGReplyMessage->Rpc.Buffer;
|
|
WMSGReplyMessage->LpcHeader.u2.ZeroInit = 0;
|
|
WMSGReplyMessage->Rpc.RpcHeader.Flags = WMSG_BUFFER_IMMEDIATE;
|
|
WMSGReplyMessage->LpcHeader.u1.s1.DataLength = Align4(Message->BufferLength)
|
|
+ sizeof(WMSG_RPC_HEADER);
|
|
return(RPC_S_OK);
|
|
}
|
|
else
|
|
{
|
|
Message->Buffer = RpcpFarAllocate(Message->BufferLength);
|
|
if ( Message->Buffer == 0 )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
WMSGReplyMessage->Rpc.RpcHeader.Flags = WMSG_BUFFER_SERVER;
|
|
WMSGReplyMessage->Rpc.Request.CountDataEntries = 1;
|
|
WMSGReplyMessage->LpcHeader.u2.ZeroInit = 0;
|
|
|
|
if (Flags & WMSG_SYNC_CLIENT)
|
|
{
|
|
GlobalMutexRequest() ;
|
|
BufferKey = Association->Buffers.Insert(Message->Buffer) ;
|
|
GlobalMutexClear() ;
|
|
|
|
if (BufferKey == -1)
|
|
{
|
|
RpcpFarFree(Message->Buffer) ;
|
|
return STATUS_NO_MEMORY ;
|
|
}
|
|
|
|
WMSGReplyMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_RPC_HEADER) + sizeof(WMSG_SERVER_BUFFER) ;
|
|
WMSGReplyMessage->Rpc.Server.Length = Message->BufferLength ;
|
|
WMSGReplyMessage->Rpc.Server.Buffer = (unsigned int) BufferKey ;
|
|
}
|
|
else
|
|
{
|
|
WMSGReplyMessage->LpcHeader.MessageId = 0;
|
|
WMSGReplyMessage->LpcHeader.CallbackId = 0;
|
|
WMSGReplyMessage->LpcHeader.u2.s2.DataInfoOffset =
|
|
sizeof(PORT_MESSAGE) + sizeof(WMSG_RPC_HEADER);
|
|
WMSGReplyMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_RPC_HEADER) + sizeof(PORT_DATA_INFORMATION);
|
|
WMSGReplyMessage->Rpc.Request.DataEntries[0].Base = Message->Buffer;
|
|
WMSGReplyMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
WMSG_SCALL::FreeBuffer (
|
|
IN PRPC_MESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will free the supplied buffer.
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the buffer to be freed.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(WMSGReplyMessage != NULL) ;
|
|
if ( Message->Buffer == WMSGRequestMessage->Rpc.Buffer ||
|
|
Message->Buffer == WMSGReplyMessage->Rpc.Buffer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GlobalMutexRequest();
|
|
Association->Buffers.DeleteItemByBruteForce(Message->Buffer);
|
|
GlobalMutexClear();
|
|
|
|
RpcpFarFree(Message->Buffer);
|
|
}
|
|
|
|
void
|
|
WMSG_SCALL::FreePipeBuffer (
|
|
IN PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
RpcpFarFree(Message->Buffer) ;
|
|
}
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::ReallocPipeBuffer (
|
|
IN PRPC_MESSAGE Message,
|
|
IN unsigned int NewSize
|
|
)
|
|
{
|
|
int BufferKey;
|
|
PVOID Buffer ;
|
|
void *NewBuffer ;
|
|
|
|
ASSERT(Flags & WMSG_SYNC_CLIENT) ;
|
|
|
|
if (NewSize > CurrentBufferLength)
|
|
{
|
|
NewBuffer = RpcpFarAllocate(NewSize) ;
|
|
if (NewBuffer == 0)
|
|
{
|
|
RpcpFarFree(Message->Buffer) ;
|
|
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
|
|
GlobalMutexRequest();
|
|
BufferKey = Association->Buffers.Insert(NewBuffer);
|
|
if ( BufferKey == -1 )
|
|
{
|
|
GlobalMutexClear();
|
|
RpcpFarFree(NewBuffer);
|
|
RpcpFarFree(Message->Buffer) ;
|
|
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
if (CurrentBufferLength > 0)
|
|
{
|
|
Buffer = Association->Buffers.Find(
|
|
WMSGReplyMessage->Rpc.Server.Buffer);
|
|
if ( Buffer != 0 )
|
|
{
|
|
Association->Buffers.Delete(
|
|
WMSGReplyMessage->Rpc.Server.Buffer);
|
|
}
|
|
}
|
|
GlobalMutexClear();
|
|
|
|
|
|
if (CurrentBufferLength > 0)
|
|
{
|
|
RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
|
|
FreePipeBuffer(Message) ;
|
|
}
|
|
Message->Buffer = NewBuffer ;
|
|
WMSGReplyMessage->Rpc.Server.Buffer = (unsigned int) BufferKey;
|
|
CurrentBufferLength = NewSize ;
|
|
}
|
|
|
|
Message->BufferLength = NewSize ;
|
|
|
|
WMSGReplyMessage->Rpc.RpcHeader.Flags = WMSG_BUFFER_SERVER;
|
|
WMSGReplyMessage->LpcHeader.u2.ZeroInit = 0;
|
|
WMSGReplyMessage->LpcHeader.u1.s1.DataLength = sizeof(WMSG_RPC_HEADER)
|
|
+ sizeof(WMSG_SERVER_BUFFER);
|
|
WMSGReplyMessage->Rpc.Server.Length = Message->BufferLength;
|
|
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::Receive (
|
|
IN PRPC_MESSAGE Message,
|
|
IN unsigned int Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Receive routine used by pipes
|
|
|
|
Arguments:
|
|
|
|
Message - contains to buffer to receive in
|
|
pSize - pointer to a size value that contains the minimum amount of
|
|
data that needs to be received.
|
|
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We have successfully converted the message.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to do the
|
|
conversion.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus ;
|
|
NTSTATUS NtStatus ;
|
|
int RequestedSize;
|
|
WMSG_MESSAGE *WMSGSavedMessage;
|
|
unsigned long Partial = Message->RpcFlags & RPC_BUFFER_PARTIAL ;
|
|
unsigned long Extra = Message->RpcFlags & RPC_BUFFER_EXTRA ;
|
|
|
|
if (BufferComplete)
|
|
{
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
if (ConnectionKey == 0)
|
|
{
|
|
RpcStatus = SetupForPipes() ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return RpcStatus ;
|
|
}
|
|
|
|
RpcStatus = SendAck(WMSGRequestMessage, 0) ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return RpcStatus ;
|
|
}
|
|
}
|
|
|
|
if (Extra)
|
|
{
|
|
RequestedSize = Message->BufferLength + Size ;
|
|
}
|
|
else
|
|
{
|
|
RequestedSize = Size ;
|
|
}
|
|
|
|
// the first receive has already completed
|
|
// we have inserted this connection in the connection
|
|
// dictionary in the association
|
|
|
|
while (1)
|
|
{
|
|
RpcStatus = ReadData(Message, Extra) ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return RpcStatus ;
|
|
}
|
|
|
|
if ((Message->RpcFlags & RPC_BUFFER_COMPLETE ) ||
|
|
(Partial && Message->BufferLength >= RequestedSize))
|
|
{
|
|
break;
|
|
}
|
|
|
|
Extra = 1 ;
|
|
}
|
|
|
|
ASSERT(Message->RpcFlags & RPC_BUFFER_COMPLETE
|
|
|| (NOT_MULTIPLE_OF_EIGHT(Message->BufferLength) == 0)) ;
|
|
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::Send (
|
|
IN OUT PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus ;
|
|
NTSTATUS NtStatus ;
|
|
int LengthSoFar = 0 ;
|
|
int RemainingLength = 0;
|
|
int LengthWritten ;
|
|
|
|
if (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
|
|
{
|
|
return (RPC_S_SEND_INCOMPLETE) ;
|
|
}
|
|
|
|
if (FirstSend)
|
|
{
|
|
FirstSend = 0;
|
|
|
|
if (ConnectionKey == 0)
|
|
{
|
|
RpcStatus = SetupForPipes() ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return RpcStatus ;
|
|
}
|
|
|
|
RpcStatus = SendAck(WMSGRequestMessage, 0) ;
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SendAck(PipeMessage) ;
|
|
}
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return RpcStatus ;
|
|
}
|
|
}
|
|
|
|
PipeSendCalled = 1;
|
|
|
|
if (NOT_MULTIPLE_OF_EIGHT(Message->BufferLength))
|
|
{
|
|
RemainingLength = Message->BufferLength & LOW_BITS ;
|
|
Message->BufferLength &= ~LOW_BITS ;
|
|
}
|
|
|
|
while (LengthSoFar < Message->BufferLength)
|
|
{
|
|
RpcStatus = WriteData((char *) Message->Buffer+LengthSoFar,
|
|
Message->BufferLength - LengthSoFar,
|
|
&LengthWritten) ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
RpcpFarFree(Message->Buffer) ;
|
|
return RpcStatus ;
|
|
}
|
|
|
|
LengthSoFar += LengthWritten ;
|
|
}
|
|
|
|
if (RemainingLength)
|
|
{
|
|
RpcpMemoryMove( Message->Buffer,
|
|
(char PAPI *) Message->Buffer + Message->BufferLength,
|
|
RemainingLength) ;
|
|
|
|
Message->BufferLength = RemainingLength ;
|
|
return (RPC_S_SEND_INCOMPLETE) ;
|
|
}
|
|
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
inline RPC_STATUS
|
|
WMSG_SCALL::GetBufferDo(
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN int NewSize,
|
|
IN BOOL fDataValid
|
|
)
|
|
{
|
|
void *NewBuffer ;
|
|
|
|
if (NewSize < CurrentBufferLength)
|
|
{
|
|
Message->BufferLength = NewSize ;
|
|
}
|
|
else
|
|
{
|
|
NewBuffer = RpcpFarAllocate(NewSize) ;
|
|
if (NewBuffer == 0)
|
|
{
|
|
RpcpFarFree(Message->Buffer) ;
|
|
|
|
Message->BufferLength = 0;
|
|
return RPC_S_OUT_OF_MEMORY ;
|
|
}
|
|
|
|
if (fDataValid && Message->BufferLength > 0)
|
|
{
|
|
RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
|
|
}
|
|
|
|
if (Message->RpcFlags & RPC_BUFFER_EXTRA)
|
|
{
|
|
ASSERT(Message->ReservedForRuntime) ;
|
|
((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer =
|
|
NewBuffer;
|
|
}
|
|
|
|
RpcpFarFree(Message->Buffer) ;
|
|
Message->Buffer = NewBuffer ;
|
|
Message->BufferLength = NewSize ;
|
|
}
|
|
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::SendReceive (
|
|
IN OUT PRPC_MESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the request and returns the response of a remote
|
|
procedure call.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The remote procedure call completed successful.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
|
remote procedure call.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
|
|
the remote procedure call.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
RPC_STATUS ExceptionCode, RpcStatus;
|
|
WMSG_MESSAGE *WMSGSavedMessage;
|
|
unsigned long NumberOfBytesRead;
|
|
RPC_MESSAGE RpcMessage ;
|
|
RPC_RUNTIME_INFO RuntimeInfo ;
|
|
|
|
|
|
// The WMSGMessage must be saved, it is in use by the stub. The current
|
|
// WMSGReplyMessage can be used for the callback request message and reply.
|
|
//
|
|
// We must:
|
|
// Save the current WMSGRequestMessage
|
|
// Make the current WMSGReplyMessage the WMSGRequestMessage
|
|
// Allocate a new WMSGReplyMessage.
|
|
|
|
WMSGSavedMessage = WMSGRequestMessage;
|
|
WMSGRequestMessage = WMSGReplyMessage;
|
|
WMSGReplyMessage = 0; // Only needed if we receive a recursive request.
|
|
|
|
Association->Address->Server->OutgoingCallback();
|
|
|
|
// NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
|
|
Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
|
|
|
|
WMSGRequestMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
|
|
+ WMSGRequestMessage->LpcHeader.u1.s1.DataLength;
|
|
WMSGRequestMessage->LpcHeader.u2.s2.Type = LPC_REQUEST;
|
|
WMSGRequestMessage->LpcHeader.ClientId = ClientId;
|
|
WMSGRequestMessage->LpcHeader.MessageId = MessageId;
|
|
WMSGRequestMessage->LpcHeader.CallbackId = CallbackId;
|
|
WMSGRequestMessage->LpcHeader.u2.s2.DataInfoOffset = DataInfoOffset;
|
|
WMSGRequestMessage->Rpc.RpcHeader.MessageType = WMSG_MSG_CALLBACK;
|
|
WMSGRequestMessage->Rpc.RpcHeader.ProcedureNumber = Message->ProcNum;
|
|
WMSGRequestMessage->Rpc.RpcHeader.PresentationContext =
|
|
SBinding->PresentationContext;
|
|
|
|
NtStatus = NtRequestWaitReplyPort(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGRequestMessage, (PORT_MESSAGE *) WMSGRequestMessage);
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
WMSGReplyMessage = WMSGRequestMessage;
|
|
WMSGRequestMessage = WMSGSavedMessage;
|
|
|
|
if ( NtStatus == STATUS_NO_MEMORY )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
if ( NtStatus == STATUS_INSUFFICIENT_RESOURCES )
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
#if DBG
|
|
|
|
if ( ( NtStatus != STATUS_INVALID_PORT_HANDLE )
|
|
&& ( NtStatus != STATUS_INVALID_HANDLE )
|
|
&& ( NtStatus != STATUS_INVALID_CID )
|
|
&& ( NtStatus != STATUS_PORT_DISCONNECTED )
|
|
&& (NtStatus != STATUS_LPC_REPLY_LOST ) )
|
|
{
|
|
PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( ( NtStatus == STATUS_INVALID_PORT_HANDLE )
|
|
|| ( NtStatus == STATUS_INVALID_HANDLE )
|
|
|| ( NtStatus == STATUS_INVALID_CID )
|
|
|| ( NtStatus == STATUS_PORT_DISCONNECTED )
|
|
|| ( NtStatus == STATUS_LPC_REPLY_LOST) );
|
|
return(RPC_S_CALL_FAILED);
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
if ( WMSGRequestMessage->Rpc.RpcHeader.MessageType == WMSG_MSG_FAULT )
|
|
{
|
|
RpcStatus = WMSGRequestMessage->Fault.RpcStatus;
|
|
break;
|
|
}
|
|
|
|
if ( WMSGRequestMessage->Rpc.RpcHeader.MessageType == WMSG_MSG_RESPONSE )
|
|
{
|
|
RpcStatus = Association->WMSGMessageToRpcMessage(
|
|
WMSGRequestMessage, Message);
|
|
break;
|
|
}
|
|
|
|
if ( WMSGRequestMessage->Rpc.RpcHeader.MessageType == WMSG_MSG_PUSH )
|
|
{
|
|
ASSERT( PushedResponse == 0 );
|
|
PushedResponse = RpcpFarAllocate(
|
|
(unsigned int)
|
|
WMSGRequestMessage->Push.Response.DataEntries[0].Size);
|
|
if ( PushedResponse == 0 )
|
|
{
|
|
WMSGRequestMessage->Push.RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
NtStatus = NtReadRequestData(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGRequestMessage, 0, PushedResponse,
|
|
WMSGRequestMessage->Push.Response.DataEntries[0].Size,
|
|
&NumberOfBytesRead);
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
RpcpFarFree(PushedResponse);
|
|
WMSGRequestMessage->Push.RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( WMSGRequestMessage->Push.Response.DataEntries[0].Size
|
|
== NumberOfBytesRead );
|
|
WMSGRequestMessage->Push.RpcStatus = RPC_S_OK;
|
|
}
|
|
}
|
|
|
|
WMSGRequestMessage->LpcHeader.ClientId = ClientId;
|
|
WMSGRequestMessage->LpcHeader.MessageId = MessageId;
|
|
WMSGRequestMessage->LpcHeader.CallbackId = CallbackId;
|
|
WMSGRequestMessage->LpcHeader.u2.s2.DataInfoOffset = DataInfoOffset;
|
|
|
|
NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGRequestMessage);
|
|
}
|
|
else
|
|
{
|
|
ASSERT( WMSGRequestMessage->Rpc.RpcHeader.MessageType == WMSG_LRPC_REQUEST );
|
|
|
|
RpcStatus = Association->WMSGMessageToRpcMessage(
|
|
WMSGRequestMessage, Message);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
WMSGRequestMessage->Fault.RpcHeader.MessageType =
|
|
WMSG_MSG_FAULT;
|
|
WMSGRequestMessage->Fault.RpcStatus = WMSGMapRpcStatus(RpcStatus);
|
|
WMSGRequestMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
|
|
WMSGRequestMessage->LpcHeader.u1.s1.TotalLength =
|
|
sizeof(WMSG_FAULT_MESSAGE);
|
|
WMSGRequestMessage->LpcHeader.ClientId = ClientId;
|
|
WMSGRequestMessage->LpcHeader.MessageId = MessageId;
|
|
WMSGRequestMessage->LpcHeader.CallbackId = CallbackId;
|
|
WMSGRequestMessage->LpcHeader.u2.s2.DataInfoOffset = DataInfoOffset;
|
|
NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGRequestMessage);
|
|
}
|
|
else
|
|
{
|
|
|
|
WMSGReplyMessage = new WMSG_MESSAGE;
|
|
|
|
if (WMSGReplyMessage != 0)
|
|
{
|
|
Message->TransferSyntax = &(SBinding->TransferSyntax);
|
|
Message->ProcNum = WMSGRequestMessage->Rpc.RpcHeader.ProcedureNumber;
|
|
|
|
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
|
|
RpcMessage = *Message ;
|
|
RpcMessage.ReservedForRuntime = &RuntimeInfo ;
|
|
|
|
if ( ObjectUuidFlag != 0 )
|
|
{
|
|
RpcStatus = SBinding->RpcInterface->DispatchToStubWithObject(
|
|
&RpcMessage, &ObjectUuid, 1, &ExceptionCode);
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SBinding->RpcInterface->DispatchToStub(
|
|
&RpcMessage, 1, &ExceptionCode);
|
|
}
|
|
|
|
*Message = RpcMessage ;
|
|
|
|
// Because we must send the reply and recieve the
|
|
// reply into the same message, we just copy the
|
|
// response into the WMSGRequestMessage
|
|
|
|
RpcpMemoryCopy(WMSGRequestMessage,WMSGReplyMessage,sizeof(WMSG_MESSAGE));
|
|
delete WMSGReplyMessage;
|
|
WMSGReplyMessage = 0;
|
|
|
|
}
|
|
else
|
|
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( ( RpcStatus == RPC_S_OUT_OF_MEMORY )
|
|
|| ( RpcStatus == RPC_P_EXCEPTION_OCCURED )
|
|
|| ( RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) );
|
|
|
|
if ( RpcStatus == RPC_P_EXCEPTION_OCCURED )
|
|
{
|
|
RpcStatus = WMSGMapRpcStatus(ExceptionCode);
|
|
}
|
|
|
|
WMSGRequestMessage->Fault.RpcStatus = RpcStatus;
|
|
WMSGRequestMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
|
|
WMSGRequestMessage->LpcHeader.u1.s1.TotalLength =
|
|
sizeof(WMSG_FAULT_MESSAGE);
|
|
WMSGRequestMessage->Fault.RpcHeader.MessageType =
|
|
WMSG_MSG_FAULT;
|
|
}
|
|
else
|
|
{
|
|
WMSGRequestMessage->LpcHeader.u1.s1.TotalLength =
|
|
sizeof(PORT_MESSAGE)
|
|
+ WMSGRequestMessage->LpcHeader.u1.s1.DataLength;
|
|
WMSGRequestMessage->Rpc.RpcHeader.MessageType = WMSG_MSG_RESPONSE;
|
|
}
|
|
|
|
WMSGRequestMessage->LpcHeader.ClientId = ClientId;
|
|
WMSGRequestMessage->LpcHeader.MessageId = MessageId;
|
|
WMSGRequestMessage->LpcHeader.CallbackId = CallbackId;
|
|
WMSGRequestMessage->LpcHeader.u2.s2.DataInfoOffset = DataInfoOffset;
|
|
NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGRequestMessage);
|
|
}
|
|
}
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
if ( NtStatus == STATUS_NO_MEMORY )
|
|
{
|
|
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else if ( NtStatus == STATUS_INSUFFICIENT_RESOURCES )
|
|
{
|
|
RpcStatus = RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
|
|
#if DBG
|
|
|
|
if ( ( NtStatus != STATUS_INVALID_PORT_HANDLE )
|
|
&& ( NtStatus != STATUS_INVALID_HANDLE )
|
|
&& ( NtStatus != STATUS_INVALID_CID )
|
|
&& ( NtStatus != STATUS_PORT_DISCONNECTED )
|
|
&& ( NtStatus != STATUS_LPC_REPLY_LOST) )
|
|
{
|
|
PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( ( NtStatus == STATUS_INVALID_PORT_HANDLE )
|
|
|| ( NtStatus == STATUS_INVALID_HANDLE )
|
|
|| ( NtStatus == STATUS_INVALID_CID )
|
|
|| ( NtStatus == STATUS_PORT_DISCONNECTED )
|
|
|| ( NtStatus == STATUS_LPC_REPLY_LOST) );
|
|
RpcStatus = RPC_S_CALL_FAILED;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
Message->Handle = (RPC_BINDING_HANDLE) this;
|
|
}
|
|
|
|
ASSERT(WMSGReplyMessage == 0);
|
|
WMSGReplyMessage = WMSGRequestMessage;
|
|
WMSGRequestMessage = WMSGSavedMessage;
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::ImpersonateClient (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will impersonate the client which made the remote procedure call.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
RPC_STATUS Status;
|
|
|
|
Status = SetThreadSecurityContext((SSECURITY_CONTEXT *) ~0UL, 0);
|
|
if (RPC_S_OK != Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (fSyncClient)
|
|
{
|
|
NtStatus = NtImpersonateClientOfPort(Association->LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGRequestMessage);
|
|
|
|
if ( ( NtStatus == STATUS_INVALID_CID )
|
|
|| ( NtStatus == STATUS_PORT_DISCONNECTED )
|
|
|| ( NtStatus == STATUS_REPLY_MESSAGE_MISMATCH ) )
|
|
{
|
|
ClearThreadSecurityContext(0);
|
|
return RPC_S_NO_CONTEXT_AVAILABLE;
|
|
}
|
|
|
|
#if DBG
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
PrintToDebugger("RPC : NtImpersonateClientOfPort : %lx\n", NtStatus);
|
|
}
|
|
#endif // DBG
|
|
ASSERT( NT_SUCCESS(NtStatus) );
|
|
}
|
|
else
|
|
{
|
|
if (Association->GetToken())
|
|
{
|
|
if (SetThreadToken(NULL, Association->GetToken()) == FALSE)
|
|
{
|
|
ClearThreadSecurityContext(0);
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
}
|
|
// else: we choose to say its OK !
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::RevertToSelf (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This reverts a server thread back to itself after impersonating a client.
|
|
We just check to see if the server thread is impersonating; this optimizes
|
|
the common case.
|
|
|
|
--*/
|
|
{
|
|
HANDLE ImpersonationToken = 0;
|
|
NTSTATUS NtStatus;
|
|
|
|
if (ClearThreadSecurityContext(0))
|
|
{
|
|
NtStatus = NtSetInformationThread(NtCurrentThread(),
|
|
ThreadImpersonationToken, &ImpersonationToken, sizeof(HANDLE));
|
|
|
|
#if DBG
|
|
|
|
if ( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( NT_SUCCESS(NtStatus) );
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::IsClientLocal (
|
|
OUT unsigned int * ClientLocalFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A client using WMSG will always be local.
|
|
|
|
Arguments:
|
|
|
|
ClientLocalFlag - Returns a flag which will always be set to a non-zero
|
|
value indicating that the client is local.
|
|
|
|
--*/
|
|
{
|
|
UNUSED(this);
|
|
|
|
*ClientLocalFlag = 1;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::ConvertToServerBinding (
|
|
OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If possible, convert this call into a server binding, meaning a
|
|
binding handle pointing back to the client.
|
|
|
|
Arguments:
|
|
|
|
ServerBinding - Returns the server binding.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The server binding has successfully been created.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
|
a new binding handle.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
RPC_CHAR UuidString[37];
|
|
RPC_CHAR * StringBinding;
|
|
DWORD NetworkAddressLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
BOOL Boolean;
|
|
RPC_CHAR * NetworkAddress;
|
|
|
|
if ( ObjectUuidFlag != 0 )
|
|
{
|
|
ObjectUuid.ConvertToString(UuidString);
|
|
UuidString[36] = '\0';
|
|
}
|
|
|
|
NetworkAddress = new RPC_CHAR[NetworkAddressLength];
|
|
if ( NetworkAddress == 0 )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Boolean = GetComputerNameW(NetworkAddress, &NetworkAddressLength);
|
|
|
|
#if DBG
|
|
|
|
if ( Boolean != TRUE )
|
|
{
|
|
PrintToDebugger("RPC : GetComputerNameW : %d\n", GetLastError());
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
ASSERT( Boolean == TRUE );
|
|
|
|
RpcStatus = RpcStringBindingComposeW((ObjectUuidFlag != 0 ? UuidString : 0),
|
|
RPC_CONST_STRING("ncalrpc"), NetworkAddress, 0, 0, &StringBinding);
|
|
delete NetworkAddress;
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
return(RpcStatus);
|
|
}
|
|
|
|
RpcStatus = RpcBindingFromStringBindingW(StringBinding, ServerBinding);
|
|
RpcStringFreeW(&StringBinding);
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
void
|
|
WMSG_SCALL::InquireObjectUuid (
|
|
OUT RPC_UUID * ObjectUuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the object uuid from the call into the supplied
|
|
ObjectUuid argument.
|
|
|
|
Arguments:
|
|
|
|
ObjectUuid - Returns a copy of the object uuid passed by the client
|
|
in the remote procedure call.
|
|
|
|
--*/
|
|
{
|
|
if ( ObjectUuidFlag == 0 )
|
|
{
|
|
ObjectUuid->SetToNullUuid();
|
|
}
|
|
else
|
|
{
|
|
ObjectUuid->CopyUuid(&(this->ObjectUuid));
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::ToStringBinding (
|
|
OUT RPC_CHAR ** StringBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to convert this call into a string binding. We will ask the
|
|
address for a binding handle which we can then convert into a string
|
|
binding.
|
|
|
|
Arguments:
|
|
|
|
StringBinding - Returns the string binding for this call.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
BINDING_HANDLE * BindingHandle = Association->Address->InquireBinding();
|
|
RPC_STATUS RpcStatus;
|
|
|
|
if ( BindingHandle == 0 )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
RpcStatus = BindingHandle->ToStringBinding(StringBinding);
|
|
BindingHandle->BindingFree();
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::MonitorAssociation (
|
|
IN PRPC_RUNDOWN RundownRoutine,
|
|
IN void * Context
|
|
)
|
|
{
|
|
return(Association->MonitorAssociation(RundownRoutine, Context));
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::StopMonitorAssociation (
|
|
)
|
|
{
|
|
return(Association->StopMonitorAssociation());
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::GetAssociationContext (
|
|
OUT void ** AssociationContext
|
|
)
|
|
{
|
|
*AssociationContext = Association->AssociationContext();
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::SetAssociationContext (
|
|
IN void * Context
|
|
)
|
|
{
|
|
Association->SetAssociationContext(Context);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
inline RPC_STATUS
|
|
WMSG_SASSOCIATION::WMSGMessageToRpcMessage (
|
|
IN WMSG_MESSAGE * WMSGMessage,
|
|
OUT RPC_MESSAGE * RpcMessage,
|
|
IN int *size,
|
|
IN unsigned long Extra,
|
|
IN WMSG_SCALL *SCall
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will convert from an WMSG_MESSAGE representation of a buffer (and
|
|
its length) to an RPC_MESSAGE representation.
|
|
|
|
Arguments:
|
|
|
|
RpcMessage - Returns the RPC_MESSAGE representation.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We have successfully converted the message.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to do the
|
|
conversion.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
unsigned long NumberOfBytesRead;
|
|
WMSG_MESSAGE ReplyMessage ;
|
|
unsigned char MessageType = WMSGMessage->Rpc.RpcHeader.MessageType;
|
|
void *Temp ;
|
|
char *RecvBuffer = 0;
|
|
int TotalLength ;
|
|
|
|
if(WMSGMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_IMMEDIATE)
|
|
{
|
|
RpcMessage->Buffer = WMSGMessage->Rpc.Buffer;
|
|
ASSERT(WMSGMessage->LpcHeader.u1.s1.DataLength
|
|
>= sizeof(WMSG_RPC_HEADER));
|
|
RpcMessage->BufferLength =
|
|
(unsigned int) WMSGMessage->LpcHeader.u1.s1.DataLength
|
|
- sizeof(WMSG_RPC_HEADER);
|
|
RpcMessage->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|
}
|
|
else if (WMSGMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_REQUEST)
|
|
{
|
|
TotalLength = WMSGMessage->Rpc.Request.DataEntries[0].Size;
|
|
|
|
if (!(WMSGMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_PARTIAL))
|
|
{
|
|
RpcMessage->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|
}
|
|
|
|
RpcMessage->Buffer = RpcpFarAllocate(TotalLength) ;
|
|
if (RpcMessage->Buffer == 0)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
RpcMessage->BufferLength = TotalLength ;
|
|
RecvBuffer = (char *) RpcMessage->Buffer ;
|
|
|
|
ASSERT(RecvBuffer) ;
|
|
|
|
NtStatus = NtReadRequestData(LpcServerPort,
|
|
(PORT_MESSAGE *) WMSGMessage, 0, RecvBuffer,
|
|
TotalLength, &NumberOfBytesRead) ;
|
|
|
|
if (NT_ERROR(NtStatus))
|
|
{
|
|
RpcpFarFree(RpcMessage->Buffer) ;
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
ASSERT(TotalLength == NumberOfBytesRead) ;
|
|
|
|
if ((WMSGMessage->Rpc.RpcHeader.Flags & WMSG_SYNC_CLIENT) == 0)
|
|
{
|
|
WMSGMessage->Ack.MessageType = WMSG_MSG_ACK ;
|
|
WMSGMessage->LpcHeader.u1.s1.DataLength =
|
|
sizeof(WMSG_ACK_MESSAGE) - sizeof(PORT_MESSAGE) ;
|
|
WMSGMessage->LpcHeader.u1.s1.TotalLength =
|
|
sizeof(WMSG_ACK_MESSAGE) ;
|
|
|
|
// setup the reply message
|
|
NtStatus = NtReplyPort(LpcServerPort, (PORT_MESSAGE *) WMSGMessage) ;
|
|
|
|
//BUGBUG: why is this here ?? I don't remember anymore...
|
|
WMSGMessage->Rpc.RpcHeader.MessageType = MessageType ;
|
|
|
|
if ( NT_ERROR(NtStatus) )
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSGRPC: NtReadRequestData failed: 0x%X\n",
|
|
NtStatus) ;
|
|
#endif
|
|
RpcpFarFree(RpcMessage->Buffer);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT((WMSGMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_IMMEDIATE)
|
|
|| (WMSGMessage->Rpc.RpcHeader.Flags & WMSG_BUFFER_REQUEST));
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
WMSG_SCALL::InquireAuthClient (
|
|
OUT RPC_AUTHZ_HANDLE PAPI * Privileges,
|
|
OUT RPC_CHAR PAPI * PAPI * ServerPrincipalName, OPTIONAL
|
|
OUT unsigned long PAPI * AuthenticationLevel,
|
|
OUT unsigned long PAPI * AuthenticationService,
|
|
OUT unsigned long PAPI * AuthorizationService
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Each protocol module must define this routine: it is used to obtain
|
|
the authentication and authorization information about a client making
|
|
the remote procedure call represented by this.
|
|
|
|
Arguments:
|
|
|
|
Privileges - Returns a the privileges of the client.
|
|
|
|
ServerPrincipalName - Returns the server principal name which the client
|
|
specified.
|
|
|
|
AuthenticationLevel - Returns the authentication level requested by
|
|
the client.
|
|
|
|
AuthenticationService - Returns the authentication service requested by
|
|
the client.
|
|
|
|
AuthorizationService - Returns the authorization service requested by
|
|
the client.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_CANNOT_SUPPORT - This value will always be returned.
|
|
|
|
--*/
|
|
{
|
|
SID_NAME_USE name ;
|
|
char *buf = NULL;
|
|
int bufflen = 64 ;
|
|
RPC_CHAR *username = NULL, *domainname = NULL;
|
|
unsigned long domainlen = DOMAIN_NAME_LEN ;
|
|
unsigned long userlength = USER_NAME_LEN ;
|
|
unsigned long olddomainlen, olduserlen, length ;
|
|
RPC_STATUS Status = RPC_S_OK ;
|
|
|
|
if(ARGUMENT_PRESENT(Privileges))
|
|
{
|
|
if (Association->TokenHandle == 0)
|
|
{
|
|
return RPC_S_CANNOT_SUPPORT ;
|
|
}
|
|
|
|
if (Association->UserName == 0)
|
|
{
|
|
RequestGlobalMutex() ;
|
|
if (Association->UserName == 0)
|
|
{
|
|
buf = (char PAPI *) RpcpFarAllocate(bufflen) ;
|
|
if (buf == 0)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
if (GetTokenInformation(Association->TokenHandle, TokenUser,
|
|
buf, bufflen, &length) == FALSE)
|
|
{
|
|
if (length > bufflen)
|
|
{
|
|
bufflen = length ;
|
|
RpcpFarFree(buf) ;
|
|
|
|
buf = (char PAPI *) RpcpFarAllocate(bufflen) ;
|
|
if (buf == 0)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("WMSG: GetTokenInformation failed\n") ;
|
|
#endif
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
username = (RPC_CHAR PAPI *) RpcpFarAllocate(
|
|
userlength * sizeof(RPC_CHAR)) ;
|
|
if (username == 0)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
|
|
domainlen += userlength ;
|
|
domainname = (RPC_CHAR PAPI *) RpcpFarAllocate(
|
|
domainlen * sizeof(RPC_CHAR)) ;
|
|
if (domainname == 0)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
|
|
olddomainlen = domainlen ;
|
|
olduserlen = userlength ;
|
|
|
|
while (1)
|
|
{
|
|
if (LookupAccountSidW(NULL, ((TOKEN_USER *) buf)->User.Sid,
|
|
username, &userlength, domainname, &domainlen,
|
|
&name) == FALSE)
|
|
{
|
|
if (userlength > olduserlen || domainlen > olddomainlen)
|
|
{
|
|
if (userlength > olduserlen)
|
|
{
|
|
olduserlen = userlength ;
|
|
RpcpFarFree(username) ;
|
|
|
|
username = (RPC_CHAR PAPI *) RpcpFarAllocate(
|
|
userlength * sizeof(RPC_CHAR)) ;
|
|
if (username == 0)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
}
|
|
|
|
domainlen += userlength ;
|
|
olddomainlen = domainlen ;
|
|
|
|
RpcpFarFree(domainname) ;
|
|
|
|
domainname = (RPC_CHAR PAPI *) RpcpFarAllocate(
|
|
domainlen * sizeof(RPC_CHAR)) ;
|
|
if (domainname == 0)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(Association->UserName == NULL);
|
|
#if DBG
|
|
PrintToDebugger("WMSG: LookupAccountSid failed\n") ;
|
|
#endif
|
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|
goto cleanup ;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
RpcpStringConcatenate(domainname, RPC_CONST_STRING("\\")) ;
|
|
RpcpStringConcatenate(domainname, username) ;
|
|
|
|
RpcpFarFree(username) ;
|
|
RpcpFarFree(buf) ;
|
|
Association->UserName = domainname ;
|
|
}
|
|
cleanup:
|
|
GlobalMutexClear() ;
|
|
|
|
if (Status)
|
|
{
|
|
|
|
if (buf) RpcpFarFree(buf) ;
|
|
if (username) RpcpFarFree(username) ;
|
|
if (domainname) RpcpFarFree(domainname) ;
|
|
|
|
return Status ;
|
|
}
|
|
}
|
|
*Privileges = Association->UserName ;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ServerPrincipalName))
|
|
{
|
|
*ServerPrincipalName = NULL;
|
|
}
|
|
|
|
if(ARGUMENT_PRESENT(AuthenticationLevel))
|
|
{
|
|
*AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY ;
|
|
}
|
|
|
|
if(ARGUMENT_PRESENT(AuthenticationService))
|
|
{
|
|
*AuthenticationService = RPC_C_AUTHN_WINNT ;
|
|
}
|
|
|
|
if(ARGUMENT_PRESENT(AuthorizationService))
|
|
{
|
|
*AuthorizationService = RPC_C_AUTHZ_NONE ;
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_ADDRESS *
|
|
WmsgCreateRpcAddress (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We just to create a new WMSG_ADDRESS. This routine is a proxy for the
|
|
new constructor to isolate the other modules.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|
RPC_ADDRESS * RpcAddress;
|
|
|
|
RpcAddress = new WMSG_ADDRESS(&RpcStatus);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
return(0);
|
|
}
|
|
return(RpcAddress);
|
|
}
|