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.
1180 lines
24 KiB
1180 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Process.cxx
|
|
|
|
Abstract:
|
|
|
|
Process objects represent local clients and servers. These
|
|
objects live as context handles.
|
|
|
|
There are relatively few of these objects in the universe.
|
|
|
|
Author:
|
|
|
|
Mario Goertzel [MarioGo]
|
|
|
|
Revision History:
|
|
|
|
MarioGo 02-20-95 Bits 'n pieces
|
|
|
|
--*/
|
|
|
|
#include <or.hxx>
|
|
|
|
CRITICAL_SECTION gcsFastProcessLock;
|
|
|
|
void
|
|
CProcess::Rundown()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The client process has rundown. This means there are no more
|
|
client refernces which means we are free to clean things up
|
|
as long as server OXIDs still holding references won't get
|
|
upset. They all use the server lock when accessing the process.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CClassReg *pReg;
|
|
ORSTATUS status;
|
|
|
|
gpServerLock->LockExclusive();
|
|
|
|
ASSERT(_cClientReferences == 0);
|
|
|
|
OrDbgDetailPrint(("OR: Rundown of %p: %d oxids, %d oids and %d roxids left\n",
|
|
this,
|
|
_blistOxids.Size(),
|
|
_blistOids.Size(),
|
|
_blistRemoteOxids.Size() ));
|
|
|
|
// Revoke any class registrations which were registered but not already
|
|
// revoked.
|
|
while ( (pReg = (CClassReg *)_listClasses.First()) != 0 )
|
|
{
|
|
SCMRemoveRegistration( pReg->Clsid,
|
|
GetToken()->GetSid(),
|
|
pReg->Reg );
|
|
_listClasses.Remove((CListElement *)pReg);
|
|
delete pReg;
|
|
}
|
|
|
|
// Release any OXIDs owned by this process. This may destroy the OXID.
|
|
// This will release this CProcess, but won't release the last reference as
|
|
// the client process still owns one.
|
|
|
|
|
|
if (_blistOxids.Size())
|
|
{
|
|
CServerOxid *poxid;
|
|
|
|
CBListIterator oxids(&_blistOxids);
|
|
|
|
while(poxid = (CServerOxid *)oxids.Next())
|
|
{
|
|
gpServerOxidTable->Remove(poxid);
|
|
poxid->ProcessRelease();
|
|
}
|
|
}
|
|
|
|
// Release any OIDs is use by this processes.
|
|
|
|
// Do this now, rather then waiting for the last server oid
|
|
// owned by this process to get invalidated and rundown.
|
|
|
|
gpClientLock->LockExclusive();
|
|
|
|
// *** Both client and server lock held here. ***
|
|
|
|
if (_blistOids.Size())
|
|
{
|
|
CClientOid *poid;
|
|
|
|
CBListIterator oids(&_blistOids);
|
|
|
|
while(poid = (CClientOid *)oids.Next())
|
|
{
|
|
poid->ClientRelease();
|
|
}
|
|
}
|
|
|
|
if (_blistRemoteOxids.Size())
|
|
{
|
|
CClientOxid *poxid;
|
|
|
|
CBListIterator oxids(&_blistRemoteOxids);
|
|
while (poxid = (CClientOxid *)oxids.Next())
|
|
{
|
|
poxid->Release();
|
|
}
|
|
}
|
|
|
|
// Cleanup other process state.
|
|
|
|
_pToken->Release();
|
|
_pToken = 0;
|
|
|
|
gpClientLock->UnlockExclusive();
|
|
|
|
// Done, release the clients' reference, this may actually delete this
|
|
// process. (If an OXID still exists and has OIDs it will not be deleted
|
|
// until the OIDs all rundown).
|
|
|
|
this->Release();
|
|
|
|
// The this pointer maybe invalid now.
|
|
|
|
gpServerLock->UnlockExclusive();
|
|
}
|
|
|
|
|
|
CProcess::CProcess(
|
|
IN CToken *pToken,
|
|
OUT ORSTATUS &status
|
|
) :
|
|
_blistOxids(4),
|
|
_blistOids(16),
|
|
_blistRemoteOxids(4),
|
|
_listClasses()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initalized a process object, members and add it to the
|
|
process list.
|
|
|
|
Arguments:
|
|
|
|
pToken - The clients token. We assume we have a reference.
|
|
|
|
status - Sometimes the C'tor can fail with OR_NOMEM.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
_cClientReferences = 1;
|
|
_hProcess = NULL;
|
|
_fCacheFree = FALSE;
|
|
_pdsaLocalBindings = NULL;
|
|
_pdsaRemoteBindings = NULL;
|
|
_pToken = 0;
|
|
|
|
status = RtlInitializeCriticalSection(&_csCallbackLock);
|
|
_fLockValid = (status == STATUS_SUCCESS);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
CMutexLock lock(&gcsProcessManagerLock);
|
|
status = gpProcessList->Insert(this);
|
|
}
|
|
|
|
if (status == OR_OK)
|
|
_pToken = pToken;
|
|
|
|
#if DBG
|
|
_cRundowns = 0;
|
|
#endif
|
|
}
|
|
|
|
CProcess::~CProcess(void)
|
|
// You probably should be looking in the ::Rundown method.
|
|
// This process object stays alive until the last server oxid dies.
|
|
{
|
|
ASSERT(gpServerLock->HeldExclusive());
|
|
ASSERT(_pToken == 0);
|
|
|
|
delete _pdsaLocalBindings;
|
|
delete _pdsaRemoteBindings;
|
|
|
|
if (_fLockValid)
|
|
DeleteCriticalSection(&_csCallbackLock);
|
|
|
|
if (_hProcess)
|
|
{
|
|
RPC_STATUS status = RpcBindingFree(&_hProcess);
|
|
ASSERT(status == RPC_S_OK);
|
|
ASSERT(_hProcess == 0);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
RPC_STATUS
|
|
CProcess::ProcessBindings(
|
|
IN DUALSTRINGARRAY *pdsaStringBindings,
|
|
IN DUALSTRINGARRAY *pdsaSecurityBindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates the string and optionally the security
|
|
bindings associated with this process.
|
|
|
|
Arguments:
|
|
|
|
psaStringBindings - The expanded string bindings of the process
|
|
|
|
psaSecurityBindings - compressed security bindings of the process.
|
|
If NULL, the current security bindings are reused.
|
|
|
|
Environment:
|
|
|
|
Server lock held during call or called from an OXID with an extra
|
|
reference owned by the process and keeping this process alive.
|
|
|
|
Return Value:
|
|
|
|
OR_NOMEM - unable to allocate storage for the new string arrays.
|
|
|
|
OR_OK - normally.
|
|
|
|
--*/
|
|
{
|
|
CMutexLock lock(&gcsFastProcessLock);
|
|
USHORT wSecSize;
|
|
PWSTR pwstrSecPointer;
|
|
|
|
// NULL security bindings means we should use the existing bindings.
|
|
if (0 == pdsaSecurityBindings)
|
|
{
|
|
ASSERT(_pdsaLocalBindings);
|
|
wSecSize = _pdsaLocalBindings->wNumEntries - _pdsaLocalBindings->wSecurityOffset;
|
|
pwstrSecPointer = _pdsaLocalBindings->aStringArray
|
|
+ _pdsaLocalBindings->wSecurityOffset;
|
|
}
|
|
else
|
|
{
|
|
wSecSize = pdsaSecurityBindings->wNumEntries - pdsaSecurityBindings->wSecurityOffset;
|
|
pwstrSecPointer = &pdsaSecurityBindings->aStringArray[pdsaSecurityBindings->wSecurityOffset];
|
|
}
|
|
|
|
DUALSTRINGARRAY *pdsaT = CompressStringArray(pdsaStringBindings);
|
|
if (!pdsaT)
|
|
{
|
|
return(OR_NOMEM);
|
|
}
|
|
|
|
// ignore security on string binding parameter
|
|
pdsaT->wNumEntries = pdsaT->wSecurityOffset;
|
|
|
|
DUALSTRINGARRAY *pdsaResult = new((pdsaT->wNumEntries + wSecSize) * sizeof(WCHAR)) DUALSTRINGARRAY;
|
|
|
|
if (0 == pdsaResult)
|
|
{
|
|
delete pdsaT;
|
|
return(OR_NOMEM);
|
|
}
|
|
|
|
pdsaResult->wNumEntries = pdsaT->wNumEntries + wSecSize;
|
|
pdsaResult->wSecurityOffset = pdsaT->wSecurityOffset;
|
|
|
|
OrMemoryCopy(pdsaResult->aStringArray,
|
|
pdsaT->aStringArray,
|
|
pdsaT->wSecurityOffset*sizeof(WCHAR));
|
|
|
|
OrMemoryCopy(pdsaResult->aStringArray + pdsaResult->wSecurityOffset,
|
|
pwstrSecPointer,
|
|
wSecSize*sizeof(WCHAR));
|
|
|
|
ASSERT(dsaValid(pdsaResult));
|
|
|
|
delete pdsaT;
|
|
|
|
delete _pdsaLocalBindings;
|
|
_pdsaLocalBindings = pdsaResult;
|
|
|
|
delete _pdsaRemoteBindings;
|
|
_pdsaRemoteBindings = 0;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
DUALSTRINGARRAY *
|
|
CProcess::GetLocalBindings(void)
|
|
// Server lock held or called within an
|
|
// OXID with an extra reference.
|
|
{
|
|
CMutexLock lock(&gcsFastProcessLock);
|
|
|
|
if (0 == _pdsaLocalBindings)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
DUALSTRINGARRAY *T = (DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY)
|
|
+ sizeof(USHORT) * _pdsaLocalBindings->wNumEntries);
|
|
|
|
if (0 != T)
|
|
{
|
|
dsaCopy(T, _pdsaLocalBindings);
|
|
}
|
|
|
|
return(T);
|
|
}
|
|
|
|
DUALSTRINGARRAY *
|
|
CProcess::GetRemoteBindings(void)
|
|
// Server lock held.
|
|
{
|
|
CMutexLock lock(&gcsFastProcessLock);
|
|
|
|
ORSTATUS Status;
|
|
|
|
if (0 == _pdsaRemoteBindings)
|
|
{
|
|
if (0 == _pdsaLocalBindings)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
Status = ConvertToRemote(_pdsaLocalBindings, &_pdsaRemoteBindings);
|
|
|
|
if (Status != OR_OK)
|
|
{
|
|
ASSERT(Status == OR_NOMEM);
|
|
return(0);
|
|
}
|
|
ASSERT(dsaValid(_pdsaRemoteBindings));
|
|
}
|
|
|
|
DUALSTRINGARRAY *T = (DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY)
|
|
+ sizeof(USHORT) * _pdsaRemoteBindings->wNumEntries);
|
|
|
|
if (0 != T)
|
|
{
|
|
dsaCopy(T, _pdsaRemoteBindings);
|
|
}
|
|
|
|
ASSERT(dsaValid(T));
|
|
return(T);
|
|
}
|
|
|
|
|
|
ORSTATUS
|
|
CProcess::AddOxid(CServerOxid *pOxid)
|
|
{
|
|
ASSERT(gpServerLock->HeldExclusive());
|
|
|
|
pOxid->Reference();
|
|
|
|
ASSERT(_blistOxids.Member(pOxid) == FALSE);
|
|
|
|
ORSTATUS status = _blistOxids.Insert(pOxid);
|
|
|
|
if (status != OR_OK)
|
|
{
|
|
pOxid->ProcessRelease();
|
|
return(status);
|
|
}
|
|
|
|
gpServerOxidTable->Add(pOxid);
|
|
|
|
return(OR_OK);
|
|
}
|
|
|
|
BOOL
|
|
CProcess::RemoveOxid(CServerOxid *poxid)
|
|
{
|
|
ASSERT(gpServerLock->HeldExclusive());
|
|
|
|
CServerOxid *pit = (CServerOxid *)_blistOxids.Remove(poxid);
|
|
|
|
if (pit)
|
|
{
|
|
ASSERT(pit == poxid);
|
|
gpServerOxidTable->Remove(poxid);
|
|
poxid->ProcessRelease();
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
ORSTATUS
|
|
CProcess::AddRemoteOxid(
|
|
IN CClientOxid *poxid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a client OXID to the set of OXIDs in use by the client
|
|
process. OXIDs are added during resolve and removed during
|
|
bulk update or when the process dies.
|
|
|
|
Arguments:
|
|
|
|
poxid - the OXID at add. Will reference the OXID if
|
|
successful.
|
|
|
|
Return Value:
|
|
|
|
OR_NOMEM
|
|
|
|
--*/
|
|
{
|
|
ASSERT(gpClientLock->HeldExclusive());
|
|
|
|
poxid->Reference();
|
|
|
|
ORSTATUS status = _blistRemoteOxids.Insert(poxid);
|
|
|
|
if (status != OR_OK)
|
|
{
|
|
poxid->Release();
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
void
|
|
CProcess::RemoveRemoteOxid(
|
|
IN CClientOxid *poxid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an oxid from the set of oxids in use by this process.
|
|
|
|
Arguments:
|
|
|
|
poxid - The oxid to remove.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ASSERT(gpClientLock->HeldExclusive());
|
|
|
|
CClientOxid *pit = (CClientOxid *)_blistRemoteOxids.Remove(poxid);
|
|
|
|
if (pit)
|
|
{
|
|
ASSERT(pit == poxid);
|
|
poxid->Release();
|
|
}
|
|
else
|
|
{
|
|
OrDbgPrint(("OR: Process %p removed oxid %p which it didn't own\n",
|
|
this, poxid));
|
|
ASSERT(0); // BUGBUG
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CProcess::IsOwner(CServerOxid *poxid)
|
|
{
|
|
ASSERT(gpServerLock->HeldExclusive());
|
|
|
|
return (_blistOxids.Member(poxid));
|
|
}
|
|
|
|
ORSTATUS
|
|
CProcess::AddOid(CClientOid *poid)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a new oid to the list of OIDs owned by this process.
|
|
|
|
Arguments:
|
|
|
|
poid - the oid to add. It's reference is transferred to this
|
|
function. If this function fails, it must dereference the oid.
|
|
The caller passed a client reference to this process. The
|
|
process must eventually call ClientRelease() on the parameter.
|
|
|
|
Return Value:
|
|
|
|
OR_OK - normally
|
|
|
|
OR_NOMEM - out of memory.
|
|
|
|
--*/
|
|
|
|
{
|
|
ORSTATUS status;
|
|
|
|
ASSERT(gpClientLock->HeldExclusive());
|
|
|
|
status = _blistOids.Insert(poid);
|
|
|
|
if (status != OR_OK)
|
|
{
|
|
ASSERT(status == OR_NOMEM);
|
|
poid->ClientRelease();
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
CClientOid *
|
|
CProcess::RemoveOid(CClientOid *poid)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an OID from this list of OID in use by this process.
|
|
|
|
Arguments:
|
|
|
|
poid - The OID to remove.
|
|
|
|
Return Value:
|
|
|
|
non-zero - the pointer actually remove. (ASSERT(retval == poid))
|
|
It will be released by the process before return,
|
|
so you should not use the pointer unless you know you
|
|
have another reference.
|
|
|
|
0 - not in the list
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(gpClientLock->HeldExclusive());
|
|
|
|
CClientOid *pit = (CClientOid *)_blistOids.Remove(poid);
|
|
|
|
if (pit)
|
|
{
|
|
ASSERT(pit == poid);
|
|
|
|
pit->ClientRelease();
|
|
return(pit);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
CProcess::AddClassReg(GUID Clsid, DWORD Reg)
|
|
{
|
|
CClassReg * pReg;
|
|
|
|
pReg = new CClassReg( Clsid, Reg );
|
|
|
|
if (pReg)
|
|
{
|
|
gpServerLock->LockExclusive();
|
|
|
|
_listClasses.Insert((CListElement *)pReg);
|
|
|
|
gpServerLock->UnlockExclusive();
|
|
}
|
|
}
|
|
|
|
void
|
|
CProcess::RemoveClassReg(GUID Clsid, DWORD Reg)
|
|
{
|
|
CClassReg * pReg;
|
|
|
|
gpServerLock->LockExclusive();
|
|
|
|
pReg = (CClassReg *)_listClasses.First();
|
|
|
|
while ( (pReg != NULL) && (pReg->Reg != Reg) )
|
|
pReg = (CClassReg *)pReg->Next();
|
|
|
|
if (pReg)
|
|
{
|
|
(void)_listClasses.Remove((CListElement *)pReg);
|
|
delete pReg;
|
|
}
|
|
|
|
gpServerLock->UnlockExclusive();
|
|
}
|
|
|
|
RPC_BINDING_HANDLE
|
|
CProcess::GetBindingHandle(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If necessary, this function allocates a binding handle
|
|
back to process. It used either mswmsg or ncalrpc depending
|
|
on the apartmentness of the process.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Binding Handle, NULL if no valid handle.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
CMutexLock lock(&gcsFastProcessLock);
|
|
|
|
// Find ncalrpc binding.
|
|
PWSTR pwstr = _pdsaLocalBindings->aStringArray;
|
|
while(*pwstr)
|
|
{
|
|
if (*pwstr == ID_LPC)
|
|
{
|
|
break;
|
|
}
|
|
pwstr = OrStringSearch(pwstr, 0) + 1;
|
|
}
|
|
|
|
if (*pwstr == 0)
|
|
{
|
|
OrDbgPrint(("OR: Unable to find ncalrpc binding to server: %p %p\n",
|
|
_pdsaLocalBindings, this));
|
|
ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
return GetBinding(pwstr);
|
|
}
|
|
|
|
void
|
|
CProcess::EnsureRealBinding(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If necessary, this function allocates a binding handle
|
|
back to process. It used either mswmsg or ncalrpc depending
|
|
on the apartmentness of the process.
|
|
|
|
Note: Called with the server lock held -OR- from an OXID
|
|
with and extra reference which keeps this process alive.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
CMutexLock lock(&gcsFastProcessLock);
|
|
|
|
if (0 == _hProcess)
|
|
{
|
|
_hProcess = GetBindingHandle();
|
|
_fCacheFree = TRUE;
|
|
|
|
if (_hProcess)
|
|
{
|
|
status = I_RpcBindingSetAsync(_hProcess, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
RPC_BINDING_HANDLE
|
|
CProcess::AllocateBinding(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a unique binding handle for a call back
|
|
to the process. This binding handle will not be
|
|
used by another thread until it is freed.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
0 - failure
|
|
|
|
non-zero - a binding handle to use.
|
|
|
|
--*/
|
|
{
|
|
|
|
EnsureRealBinding();
|
|
|
|
if (_hProcess == 0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
CMutexLock lock(&gcsFastProcessLock);
|
|
|
|
ASSERT(_hProcess);
|
|
|
|
if (_fCacheFree)
|
|
{
|
|
_fCacheFree = FALSE;
|
|
return(_hProcess);
|
|
}
|
|
|
|
RPC_BINDING_HANDLE h;
|
|
RPC_STATUS status;
|
|
|
|
status = RpcBindingCopy(_hProcess, &h);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
status = I_RpcBindingSetAsync(h, 0);
|
|
ASSERT(status == RPC_S_OK);
|
|
|
|
return(h);
|
|
}
|
|
|
|
|
|
void
|
|
CProcess::FreeBinding(
|
|
IN RPC_BINDING_HANDLE hBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a binding back to the process.
|
|
|
|
Arguments:
|
|
|
|
hBinding - A binding back to the process previously
|
|
allocated with AllocateBinding().
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (hBinding == _hProcess)
|
|
{
|
|
_fCacheFree = TRUE;
|
|
}
|
|
else
|
|
{
|
|
RPC_STATUS status = RpcBindingFree(&hBinding);
|
|
ASSERT(status == RPC_S_OK);
|
|
}
|
|
}
|
|
|
|
void
|
|
CProcess::RundownOids(
|
|
IN USHORT cOids,
|
|
IN OID aOids[],
|
|
IN UUID ipidUnk,
|
|
OUT BYTE afRundownOk[]
|
|
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempts to callback to the process which will rundown the OIDs.
|
|
This is called from an OXID which will be kept alive during the
|
|
whole call. Multiple calls maybe made to this function by
|
|
one or more OXIDs at the same time. The callback itself is
|
|
an ORPC call, ie is must have THIS and THAT pointers.
|
|
|
|
Arguments:
|
|
|
|
cOids - The number of entries in aOids and afRundownOk
|
|
|
|
aOids - An array of cOids IDs to rundown. The OIDs must
|
|
all be owned by the same OXID.
|
|
|
|
ipidUnk - The IPID of the IRemUnknown interface to use
|
|
during the callback.
|
|
|
|
afRundownOk - An array of cOids BOOLs. Upon completion if
|
|
an entry is TRUE, the corresponding OID in aOids has
|
|
been fully rundown.
|
|
|
|
Return Value:
|
|
|
|
None - see afRundownOk parameter.
|
|
|
|
--*/
|
|
|
|
{
|
|
error_status_t status = OR_OK;
|
|
int i;
|
|
INT hint;
|
|
ORPCTHIS orpcthis;
|
|
LOCALTHIS localthis;
|
|
ORPCTHAT orpcthat;
|
|
RPC_BINDING_HANDLE hBinding;
|
|
|
|
gpServerLock->UnlockExclusive();
|
|
|
|
// This process will be held alive by the OXID calling
|
|
// us since it has an extra reference.
|
|
|
|
hBinding = AllocateBinding();
|
|
|
|
if (0 == hBinding)
|
|
{
|
|
status = OR_NOMEM;
|
|
}
|
|
|
|
#if DBG
|
|
CMutexLock lock(&_csCallbackLock);
|
|
CTime start;
|
|
_cRundowns++;
|
|
|
|
if (_cRundowns == 1)
|
|
{
|
|
_timeFirstRundown.SetNow();
|
|
}
|
|
|
|
if (start - _timeFirstRundown > 120 || _cRundowns > 10)
|
|
{
|
|
OrDbgPrint(("OR: Process %p, first rundown %d seconds ago, %d rundown threads\n",
|
|
this, start - _timeFirstRundown, _cRundowns));
|
|
}
|
|
lock.Unlock();
|
|
#endif
|
|
|
|
orpcthis.version.MajorVersion = COM_MAJOR_VERSION;
|
|
orpcthis.version.MinorVersion = COM_MINOR_VERSION;
|
|
orpcthis.flags = ORPCF_LOCAL;
|
|
orpcthis.reserved1 = 0;
|
|
orpcthis.extensions = NULL;
|
|
hint = AllocateCallId(orpcthis.cid);
|
|
localthis.dwClientThread = 0;
|
|
localthis.callcat = CALLCAT_SYNCHRONOUS;
|
|
orpcthat.flags = 0;
|
|
orpcthat.extensions = 0;
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
status = RpcBindingSetObject(hBinding, &ipidUnk);
|
|
}
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
status = RawRundownOid(
|
|
hBinding,
|
|
&orpcthis,
|
|
&localthis,
|
|
&orpcthat,
|
|
cOids,
|
|
aOids,
|
|
afRundownOk
|
|
);
|
|
}
|
|
|
|
#if DBG
|
|
lock.Lock();
|
|
CTime end;
|
|
_cRundowns--;
|
|
|
|
if (_cRundowns > 0 || (end - start > 120))
|
|
{
|
|
OrDbgPrint(("OR: Process %p: rundown status %d. %d seconds for rundown, %d waiting\n",
|
|
this, status, _cRundowns, end - start));
|
|
}
|
|
#endif
|
|
|
|
if (orpcthat.extensions)
|
|
{
|
|
for (int i = 0; i < orpcthat.extensions->size; i++)
|
|
{
|
|
MIDL_user_free(orpcthat.extensions->extent[i]);
|
|
}
|
|
MIDL_user_free(orpcthat.extensions);
|
|
}
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
OrDbgPrint(("OR: Rundown failed: (%p, %p, %p) - %d\n",
|
|
aOids, this, hBinding, status));
|
|
}
|
|
|
|
if (status == RPC_E_DISCONNECTED)
|
|
{
|
|
OrDbgPrint(("OR: Rundown returned disconnected\n"));
|
|
for(USHORT i = 0; i < cOids; i++)
|
|
{
|
|
afRundownOk[i] = TRUE;
|
|
}
|
|
status = RPC_S_OK;
|
|
}
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
for(USHORT i = 0; i < cOids; i++)
|
|
{
|
|
afRundownOk[i] = FALSE;
|
|
}
|
|
}
|
|
|
|
if (hBinding)
|
|
{
|
|
FreeBinding(hBinding);
|
|
}
|
|
|
|
FreeCallId(hint);
|
|
}
|
|
|
|
ORSTATUS
|
|
CProcess::UseProtseqIfNeeded(
|
|
IN USHORT cClientProtseqs,
|
|
IN USHORT aClientProtseqs[]
|
|
)
|
|
{
|
|
ORSTATUS status;
|
|
RPC_BINDING_HANDLE hBinding;
|
|
UUID NullUuid = { 0 };
|
|
|
|
hBinding = AllocateBinding();
|
|
|
|
if (0 == hBinding)
|
|
{
|
|
return(OR_NOMEM);
|
|
}
|
|
|
|
// This process will be held alive by the OXID calling
|
|
// us since it has an extra reference.
|
|
|
|
CMutexLock callback(&_csCallbackLock);
|
|
|
|
CMutexLock process(&gcsFastProcessLock);
|
|
|
|
// Another thread may have used the protseq in the mean time.
|
|
|
|
ASSERT(_pdsaLocalBindings);
|
|
|
|
USHORT protseq = FindMatchingProtseq(cClientProtseqs,
|
|
aClientProtseqs,
|
|
_pdsaLocalBindings->aStringArray
|
|
);
|
|
|
|
if (0 != protseq)
|
|
{
|
|
FreeBinding(hBinding);
|
|
return(OR_OK);
|
|
}
|
|
|
|
// No protseq shared between the client and the OXIDs' server.
|
|
// Find a matching protseq.
|
|
|
|
PWSTR pwstrProtseq = 0;
|
|
|
|
if (cClientProtseqs == 1 && IsLocal(aClientProtseqs[0]))
|
|
{
|
|
pwstrProtseq = GetProtseq(aClientProtseqs[0]);
|
|
ASSERT(pwstrProtseq);
|
|
}
|
|
else
|
|
{
|
|
|
|
USHORT i,j;
|
|
|
|
for(i = 0; i < cClientProtseqs && pwstrProtseq == 0; i++)
|
|
{
|
|
for(j = 0; j < cMyProtseqs; j++)
|
|
{
|
|
if (aMyProtseqs[j] == aClientProtseqs[i])
|
|
{
|
|
ASSERT(FALSE == IsLocal(aMyProtseqs[j]));
|
|
|
|
pwstrProtseq = GetProtseq(aMyProtseqs[j]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 == pwstrProtseq)
|
|
{
|
|
// No shared protseq, must be a bug since the client managed to call us.
|
|
#if DBG
|
|
if (cClientProtseqs == 0)
|
|
{
|
|
OrDbgPrint(("OR: Client OR not configured to use remote protseqs\n"));
|
|
}
|
|
else
|
|
{
|
|
OrDbgPrint(("OR: Client called on an unsupported protocol:"
|
|
"%d %p %p \n", cClientProtseqs, aClientProtseqs, aMyProtseqs));
|
|
ASSERT(0);
|
|
}
|
|
#endif
|
|
|
|
FreeBinding(hBinding);
|
|
return(OR_NOSERVER);
|
|
}
|
|
|
|
process.Unlock();
|
|
|
|
DUALSTRINGARRAY *pdsaBinding = 0;
|
|
DUALSTRINGARRAY *pdsaSecurity = 0;
|
|
|
|
status = RpcBindingSetObject(hBinding, &NullUuid);
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
status = ::UseProtseq(hBinding,
|
|
pwstrProtseq,
|
|
&pdsaBinding,
|
|
&pdsaSecurity);
|
|
}
|
|
|
|
OrDbgPrint(("OR: Lazy use protseq: %S in process %p - %d\n",
|
|
pwstrProtseq, this, status));
|
|
|
|
// Update this process' state to include the new bindings.
|
|
|
|
if (!dsaValid(pdsaBinding))
|
|
{
|
|
if (pdsaBinding)
|
|
{
|
|
OrDbgPrint(("OR: Use protseq returned an invalid dsa: %p\n",
|
|
pdsaBinding));
|
|
}
|
|
status = OR_NOMEM;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(_pdsaLocalBindings);
|
|
ASSERT(status == RPC_S_OK);
|
|
status = ProcessBindings(pdsaBinding,
|
|
pdsaSecurity);
|
|
}
|
|
|
|
if (pdsaBinding != NULL)
|
|
MIDL_user_free(pdsaBinding);
|
|
if (pdsaSecurity != NULL)
|
|
MIDL_user_free(pdsaSecurity);
|
|
|
|
FreeBinding(hBinding);
|
|
return(status);
|
|
}
|
|
|
|
CRITICAL_SECTION gcsProcessManagerLock;
|
|
CBList *gpProcessList = 0;
|
|
|
|
CProcess *
|
|
ReferenceProcess(
|
|
IN PVOID key,
|
|
IN BOOL fNotContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to find a CProcess and get a reference on it
|
|
|
|
Arguments:
|
|
|
|
key - The dword key of the process allocated in _Connect.
|
|
fNotContext - Normally the key is stored as a context handle
|
|
which means locking is unnecessary. There is an extra
|
|
refernce which is released buring context rundown which
|
|
means managers using the key as a context handle
|
|
a) Don't need to lock the process and
|
|
b) Don't need to call ReleaseProcess()
|
|
|
|
Return Value:
|
|
|
|
0 - invalid key
|
|
non-zero - The process.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(gpProcessList != 0);
|
|
CProcess *pProcess;
|
|
|
|
CMutexLock lock(&gcsProcessManagerLock);
|
|
|
|
if (gpProcessList->Member(key) == FALSE)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
pProcess = (CProcess *)key;
|
|
|
|
if (fNotContext)
|
|
{
|
|
if (pProcess->CheckSecurity() == FALSE)
|
|
{
|
|
OrDbgPrint(("OR: Process %p, security check failed on SCM call\n"));
|
|
pProcess = 0;
|
|
}
|
|
else
|
|
{
|
|
pProcess->ClientReference();
|
|
}
|
|
}
|
|
|
|
return(pProcess);
|
|
}
|
|
|
|
void ReleaseProcess(CProcess *pProcess)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases a pProcess object. This should only be called when
|
|
a process object has been referenced with the fNotContext == TRUE.
|
|
|
|
Arguments:
|
|
|
|
pProcess - the process to release. May actually be deleted.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CMutexLock lock(&gcsProcessManagerLock);
|
|
|
|
if (pProcess->ClientRelease() == 0)
|
|
{
|
|
// Process has been completly released the process,
|
|
// we'll remove it from the list now since we
|
|
// already have the lock. It may not have been added,
|
|
// so this may fail.
|
|
|
|
PVOID t = gpProcessList->Remove(pProcess);
|
|
ASSERT(t == pProcess || t == 0);
|
|
|
|
lock.Unlock();
|
|
|
|
// The client process owns one real reference which will be
|
|
// released in Rundown().
|
|
|
|
pProcess->Rundown();
|
|
}
|
|
}
|
|
|