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.
406 lines
11 KiB
406 lines
11 KiB
/* --------------------------------------------------------------------
|
|
|
|
Microsoft OS/2 LAN Manager
|
|
Copyright(c) Microsoft Corp., 1991
|
|
|
|
-------------------------------------------------------------------- */
|
|
/* --------------------------------------------------------------------
|
|
|
|
Description :
|
|
|
|
Provides RPC server side stub context management
|
|
|
|
History :
|
|
|
|
stevez 01-15-91 First bits into the bucket.
|
|
|
|
-------------------------------------------------------------------- */
|
|
|
|
#include <sysinc.h>
|
|
#include <rpc.h>
|
|
#include <rpcdcep.h>
|
|
#include <rpcndr.h>
|
|
#include <rpcssp.h>
|
|
#include <util.hxx>
|
|
#include <linklist.hxx>
|
|
#include <osfpcket.hxx>
|
|
#include <rpcuuid.hxx>
|
|
#include <binding.hxx>
|
|
#include <handle.hxx>
|
|
#include <threads.hxx>
|
|
|
|
enum { /* states for NDRCONTEXT.type */
|
|
PendingAlloc = -1, /* new context being allocated */
|
|
CompletedAlloc = 0 /* allocated context */
|
|
};
|
|
|
|
typedef struct _WIRE_CONTEXT
|
|
{
|
|
unsigned long ContextType;
|
|
UUID ContextUuid;
|
|
} WIRE_CONTEXT;
|
|
|
|
LINK_LIST(SCONTEXT,
|
|
|
|
SCONTEXTItem();
|
|
|
|
void * userContext; /* context for the user */
|
|
NDR_RUNDOWN userRunDown; /* user routine to call */
|
|
|
|
WIRE_CONTEXT NDR;
|
|
CRITICAL_SECTION CriticalSection;
|
|
void __RPC_FAR * NextServerContext;
|
|
unsigned int ReferenceCount;
|
|
unsigned int DeletedFlag;
|
|
);
|
|
|
|
typedef struct {
|
|
I_RPC_MUTEX access; /* multi thread protection */
|
|
SCONTEXTList List; /* context link list header */
|
|
} SCONTEXT;
|
|
|
|
// Server context handle
|
|
|
|
static WIRE_CONTEXT SContextNil; // all zeros
|
|
static I_RPC_MUTEX newContext = 0; // protection for new contexts
|
|
|
|
static unsigned int DontSerializeContext = 0;
|
|
|
|
#ifdef NTENV
|
|
#include <memory.h>
|
|
#endif // NTENV
|
|
|
|
|
|
void
|
|
DestoryContext( // perform association closed processing
|
|
|
|
IN SCONTEXT * pSContext // context chain to process
|
|
|
|
) //-----------------------------------------------------------------------//
|
|
{
|
|
SCONTEXTItem * pSC, *pSCNext;
|
|
|
|
// for each user created context for this assoication, call the
|
|
// rundown routine for the context
|
|
|
|
for (pSC = pSContext->List.First(); pSC; pSC = pSCNext)
|
|
{
|
|
|
|
// Only contexts which have a rundown and
|
|
// are valid are cleaned up.
|
|
|
|
if (pSC->userRunDown != Nil && pSC->userContext)
|
|
(*pSC->userRunDown)(pSC->userContext);
|
|
|
|
pSCNext = pSC->Next();
|
|
if ( DontSerializeContext == 0 )
|
|
{
|
|
DeleteCriticalSection(&(pSC->CriticalSection));
|
|
}
|
|
I_RpcFree(pSC);
|
|
}
|
|
|
|
I_RpcDeleteMutex(pSContext->access);
|
|
I_RpcFree(pSContext);
|
|
}
|
|
|
|
|
|
void
|
|
NdrAfterCallProcessing (
|
|
IN void __RPC_FAR * ServerContextList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be called after the remote procedure call has completed.
|
|
For each context handle, we will leave the critical section so that
|
|
another thread can use the context handle.
|
|
|
|
Arguments:
|
|
|
|
ServerContextList - Supplies the list of context handles.
|
|
|
|
--*/
|
|
{
|
|
SCONTEXTItem * ServerContext;
|
|
SCONTEXT * ServerContextInfo;
|
|
SCONTEXTItem * DeleteMe;
|
|
|
|
I_RpcGetAssociationContext((void **) &ServerContextInfo);
|
|
ASSERT( ServerContextInfo != 0 );
|
|
|
|
for (ServerContext = (SCONTEXTItem *) ServerContextList;
|
|
ServerContext != 0;)
|
|
{
|
|
I_RpcRequestMutex(&(ServerContextInfo->access));
|
|
ServerContext->ReferenceCount -= 1;
|
|
LeaveCriticalSection(&(ServerContext->CriticalSection));
|
|
if ( ( ServerContext->DeletedFlag != 0 )
|
|
&& ( ServerContext->ReferenceCount == 0 ) )
|
|
{
|
|
DeleteMe = ServerContext;
|
|
ServerContext = (SCONTEXTItem *) ServerContext->NextServerContext;
|
|
DeleteCriticalSection(&(DeleteMe->CriticalSection));
|
|
I_RpcFree(DeleteMe);
|
|
}
|
|
else
|
|
{
|
|
ServerContext = (SCONTEXTItem *) ServerContext->NextServerContext;
|
|
}
|
|
I_RpcClearMutex(ServerContextInfo->access);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
ByteSwapWireContext(
|
|
IN WIRE_CONTEXT PAPI * WireContext,
|
|
IN unsigned char PAPI * DataRepresentation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If necessary, the wire context will be byte swapped in place.
|
|
|
|
Arguments:
|
|
|
|
WireContext - Supplies the wire context be byte swapped and returns the
|
|
resulting byte swapped context.
|
|
|
|
DataRepresentation - Supplies the data representation of the supplied wire
|
|
context.
|
|
|
|
--*/
|
|
{
|
|
if ( ( DataConvertEndian(DataRepresentation) != 0 )
|
|
&& ( WireContext != 0 ) )
|
|
{
|
|
ByteSwapLong(WireContext->ContextType);
|
|
ByteSwapLong(WireContext->ContextUuid.Data1);
|
|
ByteSwapShort(WireContext->ContextUuid.Data2);
|
|
ByteSwapShort(WireContext->ContextUuid.Data3);
|
|
}
|
|
}
|
|
|
|
|
|
NDR_SCONTEXT RPC_ENTRY
|
|
NDRSContextUnmarshall ( // translate a NDR context to a handle
|
|
|
|
IN void *pBuff, // pointer to NDR context
|
|
IN unsigned long DataRepresentation // specifies the NDR data representation
|
|
|
|
// The stub calls this routine to lookup a NDR wire format context into
|
|
// a context handle that can be used with the other context functions
|
|
// provided for the stubs use.
|
|
) //-----------------------------------------------------------------------//
|
|
{
|
|
SCONTEXTItem * pSC;
|
|
SCONTEXT * pSContext;
|
|
THREAD * Thread;
|
|
|
|
// make sure the public structure and our private ones agree
|
|
|
|
ASSERT(((PVOID)&((SCONTEXTItem *)0)->userContext)
|
|
== ((PVOID)NDRSContextValue((NDR_SCONTEXT)0)));
|
|
|
|
ByteSwapWireContext((WIRE_CONTEXT PAPI *) pBuff,
|
|
(unsigned char PAPI *) &DataRepresentation);
|
|
|
|
I_RpcGetAssociationContext((void **) &pSContext);
|
|
|
|
if (!pSContext) // initial context list
|
|
{
|
|
|
|
// newContext is used to serialize creation of new contexts
|
|
|
|
I_RpcRequestMutex(&newContext);
|
|
I_RpcGetAssociationContext((void **) &pSContext);
|
|
|
|
if (!pSContext) // if there still isn't a context
|
|
{
|
|
|
|
pSContext = (SCONTEXT *) I_RpcAllocate(sizeof(SCONTEXT));
|
|
if (!pSContext)
|
|
{
|
|
I_RpcClearMutex(newContext);
|
|
RpcRaiseException(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
memset(pSContext,0,sizeof(SCONTEXT));
|
|
|
|
// Use the context field to point the head of the list of
|
|
// contexts and set the cleanup routine to be our own
|
|
|
|
I_RpcMonitorAssociation(I_RpcGetCurrentCallHandle(),
|
|
(PRPC_RUNDOWN) DestoryContext, pSContext);
|
|
}
|
|
|
|
I_RpcClearMutex(newContext);
|
|
}
|
|
|
|
I_RpcRequestMutex(&(pSContext->access));
|
|
|
|
if (!pBuff || memcmp(pBuff, &SContextNil, sizeof(SContextNil)) == 0)
|
|
{
|
|
// allocate a new context for the Nil GUID context
|
|
|
|
pSC = (SCONTEXTItem *) I_RpcAllocate(sizeof(SCONTEXTItem));
|
|
if (!pSC)
|
|
{
|
|
I_RpcClearMutex(pSContext->access);
|
|
RpcRaiseException(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
memset(pSC,0,sizeof(SCONTEXTItem));
|
|
pSC->NDR.ContextType = (unsigned long) PendingAlloc;
|
|
pSContext->List.Add(pSC);
|
|
if ( DontSerializeContext == 0 )
|
|
{
|
|
InitializeCriticalSection(&(pSC->CriticalSection));
|
|
pSC->ReferenceCount = 0;
|
|
pSC->DeletedFlag = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int cSearched = 0; // how far we look on this list
|
|
|
|
// search the linked list for the GUID that matchs
|
|
|
|
for (pSC = pSContext->List.First(); pSC; pSC = pSC->Next(), cSearched++)
|
|
|
|
if (memcmp(pBuff, &pSC->NDR, sizeof(WIRE_CONTEXT)) == 0)
|
|
goto found;
|
|
|
|
I_RpcClearMutex(pSContext->access);
|
|
RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
|
|
|
|
found:;
|
|
// speed optimization: put found SC at head of list
|
|
|
|
if (cSearched > 10)
|
|
{
|
|
pSC->Remove(pSContext->List);
|
|
pSContext->List.Add(pSC);
|
|
}
|
|
}
|
|
|
|
if ( DontSerializeContext == 0 )
|
|
{
|
|
pSC->ReferenceCount += 1;
|
|
}
|
|
I_RpcClearMutex(pSContext->access);
|
|
if ( DontSerializeContext == 0 )
|
|
{
|
|
EnterCriticalSection(&(pSC->CriticalSection));
|
|
I_RpcRequestMutex(&(pSContext->access));
|
|
if ( pSC->DeletedFlag != 0 )
|
|
{
|
|
LeaveCriticalSection(&(pSC->CriticalSection));
|
|
pSC->ReferenceCount -= 1;
|
|
if ( pSC->ReferenceCount == 0 )
|
|
{
|
|
DeleteCriticalSection(&(pSC->CriticalSection));
|
|
I_RpcFree(pSC);
|
|
}
|
|
I_RpcClearMutex(pSContext->access);
|
|
RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
|
|
}
|
|
I_RpcClearMutex(pSContext->access);
|
|
|
|
Thread = ThreadSelf();
|
|
ASSERT( Thread != 0 );
|
|
pSC->NextServerContext = Thread->ServerContextList;
|
|
Thread->ServerContextList = (void __RPC_FAR *) pSC;
|
|
}
|
|
|
|
return ((NDR_SCONTEXT) pSC);
|
|
}
|
|
|
|
|
|
void RPC_ENTRY
|
|
NDRSContextMarshall ( // copy out a server context
|
|
|
|
IN OUT NDR_SCONTEXT hContext, // stub context to update
|
|
OUT void *pBuff, // buffer to marshell to
|
|
IN NDR_RUNDOWN userRunDownIn // user function to bind to context
|
|
|
|
// This is called by the stubs after a OUT or IN/OUT context call. It
|
|
// will do the final allocation or delete destory contexts & marshall the
|
|
// new context to the supplied buffer
|
|
) //-----------------------------------------------------------------------//
|
|
{
|
|
#define pSC ((SCONTEXTItem *)hContext)
|
|
|
|
SCONTEXT * pSContext;
|
|
|
|
if (pSC->userContext == Nil)
|
|
{
|
|
// the server code deleted this context, thus remove this context
|
|
// from the list of active contexts
|
|
|
|
I_RpcGetAssociationContext((void **) &pSContext);
|
|
|
|
I_RpcRequestMutex(&(pSContext->access));
|
|
pSC->Remove(pSContext->List);
|
|
if ( DontSerializeContext == 0 )
|
|
{
|
|
pSC->DeletedFlag = 1;
|
|
}
|
|
else
|
|
{
|
|
I_RpcFree(pSC);
|
|
}
|
|
hContext = Nil;
|
|
|
|
I_RpcClearMutex(pSContext->access);
|
|
}
|
|
|
|
if (!pSC) // return Nil content when deleted
|
|
{
|
|
memcpy(pBuff, &SContextNil, sizeof(WIRE_CONTEXT));
|
|
return;
|
|
}
|
|
|
|
if (pSC->NDR.ContextType == PendingAlloc)
|
|
{
|
|
|
|
pSC->userRunDown = userRunDownIn;
|
|
|
|
// this is a new context, allocate the GUID now
|
|
|
|
pSC->NDR.ContextType = CompletedAlloc;
|
|
|
|
#ifdef DOSWIN32RPC
|
|
UuidCreate((UUID PAPI *) &(pSC->NDR.ContextUuid));
|
|
#else
|
|
I_UuidCreate((UUID PAPI *) &(pSC->NDR.ContextUuid));
|
|
#endif
|
|
}
|
|
|
|
memcpy(pBuff, &pSC->NDR, sizeof(WIRE_CONTEXT));
|
|
|
|
#undef pSC
|
|
}
|
|
|
|
|
|
void RPC_ENTRY
|
|
I_RpcSsDontSerializeContext (
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
By default, context handles are serialized at the server. The spooler
|
|
makes use of a single context handle by two threads at a time. This
|
|
API is used by spoolss.exe to turn off serializing access to context
|
|
handles.
|
|
|
|
--*/
|
|
{
|
|
DontSerializeContext = 1;
|
|
}
|
|
|