428 lines
9.6 KiB
C++
428 lines
9.6 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996-1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Process.cxx
|
|
|
|
Abstract:
|
|
|
|
Process objects represent local clients and servers.
|
|
|
|
These objects are also polled by rundown threads to detect crashed processes.
|
|
|
|
Author:
|
|
|
|
Satish Thatte [SatishT]
|
|
|
|
--*/
|
|
|
|
#include <or.hxx>
|
|
|
|
// define the static members for page-based allocation
|
|
DEFINE_PAGE_ALLOCATOR(CProcess)
|
|
|
|
// define the static members for page-based allocation
|
|
DEFINE_PAGE_ALLOCATOR(CClassReg)
|
|
|
|
#if DBG
|
|
|
|
void CProcess::IsValid()
|
|
{
|
|
_MyOxids.IsValid();
|
|
_UsedOids.IsValid();
|
|
_dsaLocalBindings.IsValid();
|
|
_dsaRemoteBindings.IsValid();
|
|
References() > 0;
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|
|
CProcess::CProcess(ID ConnectId)
|
|
:
|
|
_MyOxids(4), // BUGBUG: these constants should be declared elsewhere
|
|
_UsedOids(16)
|
|
{
|
|
_processID = GetCurrentProcessId();
|
|
_Key.Init(ConnectId);
|
|
}
|
|
|
|
|
|
// This handle should be freed by the recepient
|
|
|
|
RPC_BINDING_HANDLE
|
|
CProcess::GetBindingHandle()
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
USHORT protseq;
|
|
RPC_BINDING_HANDLE hProc;
|
|
|
|
PWSTR pwstrMatch = FindMatchingProtseq(ID_WMSG, _dsaLocalBindings->aStringArray);
|
|
ASSERT(pwstrMatch);
|
|
|
|
PWSTR pwstrProtseq = GetProtseq(*pwstrMatch);
|
|
|
|
int l = OrStringLen(pwstrMatch) + OrStringLen(pwstrProtseq) + 2;
|
|
|
|
PWSTR pwstrBinding = (WCHAR *) PrivMemAlloc(l * sizeof(WCHAR));
|
|
|
|
if (!pwstrBinding)
|
|
{
|
|
return (NULL);
|
|
}
|
|
|
|
OrStringCopy(pwstrBinding, pwstrProtseq);
|
|
OrStringCat(pwstrBinding, L":");
|
|
OrStringCat(pwstrBinding, pwstrMatch + 1);
|
|
|
|
RPC_STATUS status = RpcBindingFromStringBinding(
|
|
pwstrBinding,
|
|
&hProc
|
|
);
|
|
|
|
ASSERT(status == RPC_S_OK);
|
|
PrivMemFree(pwstrBinding);
|
|
return hProc;
|
|
}
|
|
|
|
void
|
|
CProcess::Rundown()
|
|
// The process has crashed or disconnected and this object is being cleaned up.
|
|
{
|
|
COxid *pOxid;
|
|
COid *pOid;
|
|
ORSTATUS status;
|
|
|
|
CClassReg * pReg;
|
|
|
|
TCSafeLinkListIterator<CClassReg> RegIter;
|
|
RegIter.Init(_RegClasses);
|
|
|
|
for (pReg = RegIter.Next(); pReg != NULL; pReg = RegIter.Next())
|
|
{
|
|
SCMRemoveRegistration(
|
|
pReg->GetClsid(),
|
|
pReg->GetReg()
|
|
);
|
|
}
|
|
|
|
_RegClasses.Clear(); // this should drop all refcounts for CClassReg objects
|
|
// in this list to 0 and thus cause them to self-destruct
|
|
|
|
if (_MyOxids.Size())
|
|
{
|
|
COxidTableIterator Oxids(_MyOxids);
|
|
|
|
while(pOxid = Oxids.Next())
|
|
{
|
|
DisownOxid(pOxid,FALSE); // not the server thread
|
|
}
|
|
}
|
|
|
|
_UsedOids.RemoveAll();
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
CProcess::ProcessBindings(
|
|
IN DUALSTRINGARRAY *pdsaStringBindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates the string bindings associated with this process.
|
|
|
|
Arguments:
|
|
|
|
psaStringBindings - The expanded string bindings of the process
|
|
assumed to be allocated with "new" in local (not shared) memory
|
|
|
|
Return Value:
|
|
|
|
OR_NOMEM - unable to allocate storage for the new string arrays.
|
|
|
|
OR_OK - normally.
|
|
|
|
--*/
|
|
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
ORSTATUS status = OR_OK;
|
|
|
|
ASSERT(pdsaStringBindings && dsaValid(pdsaStringBindings)
|
|
&& "Process given invalid bindings to store");
|
|
|
|
status = _dsaLocalBindings.Assign(pdsaStringBindings, FALSE); // FALSE = uncompressed
|
|
|
|
delete [] (char*)pdsaStringBindings; // Assign makes a compressed copy
|
|
|
|
ASSERT(_dsaLocalBindings.Valid());
|
|
|
|
_dsaRemoteBindings.Assign(NULL,TRUE); // wipes it out -- filled again when needed
|
|
|
|
return(OR_OK);
|
|
}
|
|
|
|
|
|
|
|
DUALSTRINGARRAY *
|
|
CProcess::GetRemoteBindings(void)
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
ORSTATUS Status;
|
|
|
|
if (_dsaRemoteBindings.Empty() && !_dsaLocalBindings.Empty())
|
|
{
|
|
Status = _dsaRemoteBindings.ExtractRemote(_dsaLocalBindings);
|
|
|
|
if (Status != OR_OK)
|
|
{
|
|
ASSERT(Status == OR_NOMEM);
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
if (!_dsaRemoteBindings.Empty())
|
|
{
|
|
return _dsaRemoteBindings;
|
|
}
|
|
else return(NULL);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CProcess::DisownOxid(COxid *pOxid, BOOL fOxidThreadCalling)
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
pOxid->StopRunning();
|
|
|
|
ORSTATUS status = pOxid->StopRundownThreadIfNecessary();
|
|
ASSERT(status == OR_OK);
|
|
|
|
if (fOxidThreadCalling)
|
|
{
|
|
pOxid->StopTimerIfNecessary();
|
|
}
|
|
|
|
COxid *pIt = gpOxidTable->Remove(*pOxid);
|
|
ASSERT(pIt==pOxid);
|
|
|
|
pIt = _MyOxids.Remove(*pOxid);
|
|
ASSERT(pIt==pOxid);
|
|
|
|
// pOxid may be an invalid pointer now
|
|
}
|
|
|
|
|
|
|
|
|
|
COid *
|
|
CProcess::DropOid(COid *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-NULL - the pointer actually removed. (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.
|
|
|
|
NULL - not in the list
|
|
|
|
--*/
|
|
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
COid *pIt = _UsedOids.Remove(*pOid); // releases our reference
|
|
|
|
if (pIt)
|
|
{
|
|
ASSERT(pIt == pOid);
|
|
return(pIt);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
void
|
|
CProcess::AddClassReg(GUID Clsid, DWORD Reg)
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
CRegKey newReg(Clsid,Reg);
|
|
|
|
CClassReg * pReg = new CClassReg( Clsid, Reg );
|
|
|
|
if (pReg)
|
|
{
|
|
ORSTATUS status;
|
|
|
|
status = _RegClasses.Insert(pReg);
|
|
|
|
if (status == OR_I_DUPLICATE)
|
|
{
|
|
delete pReg;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CProcess::RemoveClassReg(GUID Clsid, DWORD Reg)
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
CClassReg * pReg = _RegClasses.Remove(CRegKey(Clsid,Reg));
|
|
}
|
|
|
|
|
|
|
|
ORSTATUS // called only within the SCMOR process
|
|
CProcess::UseProtseqIfNeeded(
|
|
IN USHORT cClientProtseqs,
|
|
IN USHORT aClientProtseqs[],
|
|
IN USHORT cInstalledProtseqs,
|
|
IN USHORT aInstalledProtseqs[],
|
|
IN DWORD dwServerTID // so we know where to call over WMSG
|
|
)
|
|
{
|
|
VALIDATE_METHOD
|
|
|
|
ORSTATUS status;
|
|
PWSTR pwstrProtseq = NULL;
|
|
|
|
// Hold a reference to self temorarily so we are not destroyed
|
|
// during this call -- in spite of giving up the shared mutex
|
|
|
|
CTempHoldRef tempRef(this);
|
|
|
|
// Another thread may have used the protseq in the mean time.
|
|
|
|
ASSERT(!_dsaLocalBindings.Empty());
|
|
|
|
pwstrProtseq = FindMatchingProtseq(cClientProtseqs,
|
|
aClientProtseqs,
|
|
_dsaLocalBindings->aStringArray
|
|
);
|
|
|
|
if (NULL != pwstrProtseq)
|
|
{
|
|
return(OR_OK);
|
|
}
|
|
|
|
// No protseq shared between the client and the OXIDs' server.
|
|
// Find a matching protseq.
|
|
|
|
USHORT i,j;
|
|
|
|
for(i = 0; i < cClientProtseqs && pwstrProtseq == NULL; i++)
|
|
{
|
|
for(j = 0; j < cInstalledProtseqs; j++)
|
|
{
|
|
if (aInstalledProtseqs[j] == aClientProtseqs[i])
|
|
{
|
|
ASSERT(FALSE == IsLocal(aInstalledProtseqs[j]));
|
|
|
|
pwstrProtseq = GetProtseq(aInstalledProtseqs[j]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL == pwstrProtseq)
|
|
{
|
|
// No shared protseq, must be a bug since the client managed to call us.
|
|
#if DBG
|
|
if (cClientProtseqs == 0)
|
|
{
|
|
ComDebOut((DEB_OXID,"OR: Client OR not configured to use remote protseqs\n"));
|
|
}
|
|
else
|
|
{
|
|
ComDebOut((DEB_OXID,"OR: Client called on an unsupported protocol: \
|
|
%d %p %p \n", cClientProtseqs, aClientProtseqs, aInstalledProtseqs));
|
|
ASSERT(0);
|
|
}
|
|
#endif
|
|
|
|
return(OR_NOSERVER);
|
|
}
|
|
|
|
DUALSTRINGARRAY *pdsaStringBindings = NULL,
|
|
*pdsaSecurityBindings = NULL,
|
|
*pdsaMergedBindings = NULL;
|
|
|
|
RPC_BINDING_HANDLE hProc;
|
|
|
|
if ((hProc = GetBindingHandle()) != NULL)
|
|
{
|
|
// set free threaded client flags and server TID for WMSG calls
|
|
status = I_RpcBindingSetAsync(hProc,NULL,dwServerTID);
|
|
status = I_RpcSetThreadParams(
|
|
TRUE, // Free threaded client
|
|
NULL, // no blocking hook
|
|
NULL // No Hwnd for reply
|
|
);
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
CTempReleaseSharedMemory temp;
|
|
|
|
// call the server to force use of pwstrProtseq
|
|
status = ::UseProtseq(hProc,
|
|
pwstrProtseq,
|
|
&pdsaStringBindings,
|
|
&pdsaSecurityBindings
|
|
);
|
|
}
|
|
|
|
RpcBindingFree(&hProc);
|
|
}
|
|
else
|
|
{
|
|
return OR_NOSERVER;
|
|
}
|
|
|
|
if (status != RPC_S_OK) return status;
|
|
|
|
OrDbgPrint(("OR: Lazy use protseq: %S in process %p - %d\n",
|
|
pwstrProtseq, this, status));
|
|
|
|
// Update this process' state to include the new bindings.
|
|
|
|
status = MergeBindings(
|
|
pdsaStringBindings,
|
|
pdsaSecurityBindings,
|
|
&pdsaMergedBindings
|
|
);
|
|
|
|
ASSERT(status == OR_OK);
|
|
status = ProcessBindings(pdsaMergedBindings);
|
|
MIDL_user_free(pdsaStringBindings);
|
|
MIDL_user_free(pdsaSecurityBindings);
|
|
|
|
return(status);
|
|
}
|
|
|
|
|