2020-09-30 17:12:29 +02:00

454 lines
9.6 KiB
C++

/*++
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>
#if DBG
void CProcess::IsValid()
{
_MyOxids.IsValid();
_UsedOids.IsValid();
_dsaLocalBindings.IsValid();
_dsaRemoteBindings.IsValid();
References() > 0;
}
#endif // DBG
CProcess::CProcess(long ConnectId)
:
_MyOxids(4), // BUGBUG: these constants should be declared elsewhere
_UsedOids(16),
_hProcess(NULL)
{
_processID = GetCurrentProcessId();
_Key.Init(ConnectId);
}
RPC_BINDING_HANDLE
CProcess::GetBindingHandle()
{
VALIDATE_METHOD
USHORT protseq;
if (_hProcess) return _hProcess;
#ifndef _CHICAGO_
protseq = ID_LPC;
#else
protseq = ID_WMSG;
#endif
PWSTR pwstrMatch = FindMatchingProtseq(protseq, _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,
&_hProcess
);
ASSERT(status == RPC_S_OK);
PrivMemFree(pwstrBinding);
return _hProcess;
}
void
CProcess::Rundown()
// The process has crashed or disconnected and this object is being cleaned up.
{
COxid *pOxid;
COid *pOid;
ORSTATUS status;
CClassReg * pReg;
while ( (pReg = _RegClasses.Pop()) != NULL )
{
#ifdef _CHICAGO_ // BUGBUG: not essential, don't bother with on NT shared resolver
SCMRemoveRegistration( pReg->_Clsid,
pReg->_Reg
);
#endif
// delete pReg; BUGBUG: do not explicitly delete refcounted objects!
}
if (_MyOxids.Size())
{
COxidTableIterator Oxids(_MyOxids);
while(pOxid = Oxids.Next())
{
DisownOxid(pOxid,FALSE); // not the server thread
}
}
_UsedOids.RemoveAll();
}
// This thing has 2 kernel traps. Best not done too often.
BOOL
CProcess::HasCrashed()
{
VALIDATE_METHOD
// the process doing the check is definitely alive
if (_processID == MyProcessId /* && _Key == Key */)
{
return FALSE;
}
HANDLE hp = OpenProcess(
PROCESS_QUERY_INFORMATION,
FALSE,
_processID
);
if (!hp) // we assume the process is terminated and gone
{
return FALSE; // BUGBUG: still not a good choice
}
// OK, we have a handle. Now do a sanity check to make sure this is
// the same process.
// BUGBUG: still no good sanity check available -- this means we may
// not have a handle to the right process -- therefore some crashes
// may go undetected. Unlikely, but possible.
// One possibility is to cache the address of gpProcess in the process
// object and do a ReadProcessMemory on the process handle as a sanity
// check -- crude but workable since Win95 has no security against it
DWORD dwExitCode;
GetExitCodeProcess(hp,&dwExitCode);
if (STILL_ACTIVE == dwExitCode)
{
return FALSE;
}
else
{
return TRUE;
}
}
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();
if (fOxidThreadCalling)
{
pOxid->StopRundownThreadIfNecessary();
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
CClassReg * pReg = new CClassReg( Clsid, Reg );
if (pReg)
{
ORSTATUS status;
_RegClasses.Insert(status,pReg);
}
}
void
CProcess::RemoveClassReg(GUID Clsid, DWORD Reg)
{
VALIDATE_METHOD
CClassReg * pReg = _RegClasses.Remove(CRegKey(Reg));
// delete pReg; BUGBUG: do not explicitly delete refcounted objects!
}
ORSTATUS // called only within the SCMOR process
CProcess::UseProtseqIfNeeded(
IN USHORT cClientProtseqs,
IN USHORT aClientProtseqs[],
IN USHORT cInstalledProtseqs,
IN USHORT aInstalledProtseqs[]
)
{
VALIDATE_METHOD
ORSTATUS status;
PWSTR pwstrProtseq = NULL;
// 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;
{
CTempReleaseSharedMemory temp;
if (GetBindingHandle() != NULL) // initialize _hProcess if necessary
{
status = ::UseProtseq(_hProcess,
pwstrProtseq,
&pdsaStringBindings,
&pdsaSecurityBindings
);
}
else
{
return OR_NOSERVER; // BUGBUG: is that the right code?
}
}
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);
}