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

522 lines
10 KiB
C++

/*++
Copyright (c) 1995-1996 Microsoft Corporation
Module Name:
ids.cxx
Abstract:
Object resolver client side class implementations. COxid, COid
classes are implemented here.
Author:
Mario Goertzel [MarioGo]
Revision History:
MarioGo 04-03-95 Combined many smaller .cxx files
MarioGo 01-05-96 Locally unique IDs
--*/
#include<or.hxx>
//
// COid methods
//
void
COid::Rundown()
{
COid *pRemoved = gpOidTable->Remove(*this);
ASSERT(pRemoved==this);
if (!_pOxid->IsLocal())
{
_pOxid->_pMid->DropClientOid(this);
}
}
//
// COxidInfo methods
//
ORSTATUS // BUGBUG: perhaps this should have OXID_INFO as the parameter type
COxidInfo::Assign(
const COxidInfo& Info
)
/*++
Routine Desciption
Makes a copy of the incoming info, including the DUALSTRINGARRAY.
Arguments:
Info - COxidInfo object to be cpied
Return Values:
OR_OK
OR_NOMEM
--*/
{
_dwTid = Info._dwTid;
_dwPid = Info._dwPid;
_dwAuthnHint = Info._dwAuthnHint;
_ipidRemUnknown = Info._ipidRemUnknown;
return _dsaBindings.Assign(Info._dsaBindings);
}
//
// COxid methods.
//
COxid::COxid(
OXID Oxid, // constructor for remote OXIDs
CMid *pMid,
USHORT wProtseq,
OXID_INFO &OxidInfo
) :
_Key(Oxid, pMid->GetMID()),
_pProcess(OR_BASED_POINTER(CProcess,gpPingProcess)),
_protseq(wProtseq),
_fApartment(FALSE),
_fRunning(TRUE),
_fRundownThreadStarted(FALSE),
_pMid(OR_BASED_POINTER(CMid,pMid)),
_fLocal(FALSE),
_hRundownThread(NULL),
_info(OxidInfo)
{
_pMid->Reference();
}
COxid::COxid( // constructor for local OXIDs
CProcess *pProcess,
OXID_INFO &OxidInfo,
BOOL fApartment
) :
_Key(AllocateId(), gLocalMID),
_pProcess(OR_BASED_POINTER(CProcess,pProcess)),
_pMid(OR_BASED_POINTER(CMid,gpLocalMid)),
_protseq(0),
_fApartment(fApartment),
_fRunning(TRUE),
_fRundownThreadStarted(FALSE),
_fLocal(TRUE),
_hRundownThread(NULL),
_info(OxidInfo)
{
_pProcess->Reference();
}
COxid::~COxid()
{
// this works even if executed by nonowner thread
StopRundownThreadIfNecessary();
// Don't release the local CMid!
if (!IsLocal()) _pMid->Release();
}
COid *
COxid::DisownOid(COid *pOid)
{
COid *pMyOid = _MyOids.Remove(*pOid);// releases our reference
if (pMyOid)
{
ASSERT(pMyOid == pOid);
return pOid;
}
return NULL;
}
void
COxid::StopRunning()
{
ReleaseAllOids();
_fRunning = FALSE;
}
void
COxid::ReleaseAllOids()
{
if (_MyOids.Size())
{
COidTableIterator Oids(_MyOids);
COid *pOid;
while(pOid = Oids.Next())
{
pOid->Rundown();
}
_MyOids.RemoveAll();
}
}
ORSTATUS
COxid::GetInfo(
OUT OXID_INFO *pInfo
)
/*++
Routine Description:
Returns the OXID_INFO structure for this oxid for local.
Arguments:
pInfo - Will contain the standard info, a single _expanded_
string binding and complete security bindings.
Return Value:
OR_NOMEM - Unable to allocate a parameter.
OR_OK - Normally.
--*/
{
USHORT protseq;
PWSTR pwstrT;
CDSA dsaBindings;
if (!IsRunning())
{
return OR_NOSERVER;
}
if (_fLocal)
{
dsaBindings.Assign(_pProcess->GetLocalBindings());
#ifndef _CHICAGO_
protseq = ID_LPC;
#else // always use WMSG on Win95 for local servers
protseq = ID_WMSG;
#endif // _CHICAGO_
}
else
{
protseq = _protseq; // use the one we set when this was created
DUALSTRINGARRAY *pdsa = _info._dsaBindings; // auto conversion
dsaBindings.Assign(pdsa); // noncopying assignment
}
pwstrT = FindMatchingProtseq(protseq, dsaBindings->aStringArray);
ASSERT(pwstrT != NULL && "OR: Didn't find a matching binding for oxid");
pInfo->psa =
GetStringBinding(
pwstrT,
dsaBindings->aStringArray + dsaBindings->wSecurityOffset
);
if (0 == pInfo->psa)
{
return OR_NOMEM;
}
pInfo->dwTid = _info._dwTid;
pInfo->dwPid = _info._dwPid;
pInfo->dwAuthnHint = _info._dwAuthnHint;
pInfo->ipidRemUnknown = _info._ipidRemUnknown;
return(OR_OK);
}
ORSTATUS
COxid::GetRemoteInfo(
IN USHORT cClientProtseqs,
IN USHORT *aClientProtseqs,
IN USHORT cInstalledProtseqs,
IN USHORT *aInstalledProtseqs,
OUT OXID_INFO *pInfo
)
/*++
Routine Description:
Returns the OXID_INFO structure for this oxid for remote clients.
Arguments:
pInfo - Will contain the standard info, a single _expanded_
string binding and complete security bindings.
Return Value:
OR_NOMEM - Unable to allocate a parameter.
OR_OK - Normally.
--*/
{
PWSTR pwstrT;
ORSTATUS status = OR_OK;
if (!IsRunning())
{
return OR_NOSERVER;
}
ASSERT(_fLocal); // Do not resolve remote servers for remote clients!
DUALSTRINGARRAY * pdsaBindings = _pProcess->GetLocalBindings();
pwstrT = FindMatchingProtseq(
cClientProtseqs,
aClientProtseqs,
pdsaBindings->aStringArray
);
if ( pwstrT == NULL ) // try lazy use of protseq(s)
{
status = _pProcess->UseProtseqIfNeeded(
cClientProtseqs,
aClientProtseqs,
cInstalledProtseqs,
aInstalledProtseqs
);
pdsaBindings = _pProcess->GetLocalBindings();
pwstrT = FindMatchingProtseq(
cClientProtseqs,
aClientProtseqs,
pdsaBindings->aStringArray
);
if ( status != OR_OK || pwstrT == NULL )
{
ComDebOut((DEB_OXID,"OR: Didn't find a matching binding for oxid %08x in mid %08x\n",
GetOXID(), GetMID()));
return OR_I_NOPROTSEQ;
}
}
DUALSTRINGARRAY *pdsaT =
GetStringBinding(
pwstrT,
pdsaBindings->aStringArray + pdsaBindings->wSecurityOffset
);
if (pdsaT != NULL)
{
pInfo->psa = CompressStringArray(pdsaT,FALSE);
MIDL_user_free(pdsaT);
}
if (NULL == pdsaT || NULL == pInfo->psa)
{
return OR_NOMEM;
}
pInfo->dwTid = 0;
pInfo->dwPid = 0;
pInfo->dwAuthnHint = _info._dwAuthnHint;
pInfo->ipidRemUnknown = _info._ipidRemUnknown;
return(status);
}
ORSTATUS
COxid::StartRundownThreadIfNecessary()
{
DWORD dwThrdId;
if (_fApartment || !IsLocal()) // rundown timer is attached to window
// or rundown handled by ping server
{
ASSERT(!_hRundownThread);
return OR_OK;
}
if (_fRundownThreadStarted) // BUGBUG: We do not want a rundown
// thread for each remote OXID
{
ASSERT(_hRundownThread);
return OR_OK;
}
_hRundownThread = CreateThread(
NULL, 0,
RundownThread,
this, 0, &dwThrdId);
if (_hRundownThread)
{
_fRundownThreadStarted = TRUE;
return OR_OK;
}
else
{
return GetLastError();
}
}
ORSTATUS
COxid::StopRundownThreadIfNecessary()
{
if (_fRundownThreadStarted)
{
ASSERT(_hRundownThread);
if (CloseHandle(_hRundownThread))
{
_fRundownThreadStarted = FALSE;
_hRundownThread = NULL;
return OR_OK;
}
else
{
return GetLastError();
}
}
else
{
ASSERT(!_hRundownThread);
return OR_OK;
}
}
ORSTATUS
COxid::StopTimerIfNecessary() // must be called by owner thread
{
ORSTATUS status = OR_OK;
if (_fApartment)
{
// find the HWND for this thread
COleTls tls;
HWND hWindow = (HWND)((OXIDEntry *)tls->pOXIDEntry)->hServerSTA;
if (!KillTimer(hWindow,IDT_DCOM_RUNDOWN))
{
status = GetLastError();
}
}
return status;
}
void
CheckForCrashedProcessesIfNecessary()
{
CTime CurrentTime;
// don't check too often
if (CurrentTime - CTime(*gpdwLastCrashedProcessCheckTime) < BasePingInterval)
{
return;
}
// timestamp the check
*gpdwLastCrashedProcessCheckTime = CurrentTime;
CProcessTableIterator procIter(*gpProcessTable);
CProcess *pNextProcess;
while (pNextProcess = procIter.Next())
{
if (pNextProcess->HasCrashed())
{
// ASSERT(0);
ComDebOut((DEB_OXID,"Process PID = %d has crashed\n",
pNextProcess->_processID));
gpProcessTable->Remove(*pNextProcess);
pNextProcess->Rundown();
}
else
{
ComDebOut((DEB_OXID,"Process PID = %d is running\n",
pNextProcess->_processID));
}
}
}
void
COxid::RundownOidsIfNecessary(
IRundown *pRemUnk
)
{
::CheckForCrashedProcessesIfNecessary();
if (_MyOids.Size() == 0) return;
COidTableIterator Oids(_MyOids);
COid *pOid;
while(pOid = Oids.Next())
{
if (pOid->OkToRundown())
{
// ASSERT(0); // BUGBUG: to debug Rundown
// COid object says OK to run down. Try to run it down.
OID Oid = pOid->GetOID();
unsigned char fOkToRundown;
if (IsLocal())
{
pRemUnk->RundownOid(1,&Oid,&fOkToRundown);
}
else
{
fOkToRundown = TRUE;
}
// If marshaller says OK to run down, get rid of it
if (fOkToRundown)
{
pOid->Rundown();
COid *pRemoved = _MyOids.Remove(*pOid);
ASSERT(pRemoved == pOid);
// At this point, the references for pOid should drop to zero
}
}
}
}