2025-04-27 07:49:33 -04:00

517 lines
14 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1997.
//
// File: iface.cxx
//
// Contents: Resolver entry points and thread definitions.
//
// Functions:
//
// History: 24-May-96 SatishT Created
//
//--------------------------------------------------------------------------
#include <or.hxx>
extern "C"
{
void FakeSapAdvertiseIfNecessary();
extern BOOL gfSapAdvertiseFailed;
}
error_status_t Connect(
OUT HPROCESS *pProcess,
OUT ULONG *pdwTimeoutInSeconds,
OUT DUALSTRINGARRAY **ppdsaOrBindings,
OUT MID *pLocalMid,
IN long cIdsToReserve,
OUT ID *pidReservedBase,
OUT ULONG *pfConnectFlags,
OUT DWORD *pAuthnLevel,
OUT DWORD *pImpLevel,
OUT DWORD *pcServerSvc,
OUT USHORT **aServerSvc,
OUT DWORD *pcClientSvc,
OUT USHORT **aClientSvc,
OUT LONG *pcChannelHook,
OUT GUID **paChannelHook,
OUT DWORD *pThreadID,
OUT DWORD *pdwRpcssProcessId
)
{
ORSTATUS status;
status = ConnectDCOM(
pProcess,
pdwTimeoutInSeconds,
pLocalMid,
pfConnectFlags,
pAuthnLevel,
pImpLevel,
pThreadID
);
CProtectSharedMemory protector; // locks through rest of lexical scope
if (status == OR_OK)
{
// Fill in channel hooks.
UpdateChannelHooks( pcChannelHook, paChannelHook );
}
if (status == OR_OK)
{
status = AllocateReservedIds(
cIdsToReserve,
pidReservedBase
);
}
if (status == OR_OK)
{
status = RemoteConnect(
ppdsaOrBindings,
pcServerSvc,
aServerSvc,
pcClientSvc,
aClientSvc,
pdwRpcssProcessId
);
}
if ( status != OR_OK && *pProcess != NULL) // Connect failure
{
gpProcessTable->Remove(**pProcess); // this drops the refcount to zero
pProcess = NULL;
}
return status;
}
//+-------------------------------------------------------------------------
//
// Method: RemoteConnect
//
// Purpose: Synchronize with the security and remote protocol
// initialization performed by RPCSS once lazily launched
//
//--------------------------------------------------------------------------
error_status_t
RemoteConnect(
OUT DUALSTRINGARRAY **ppdsaOrBindings,
OUT DWORD *pcServerSvc,
OUT USHORT **aServerSvc,
OUT DWORD *pcClientSvc,
OUT USHORT **aClientSvc,
OUT DWORD *pdwRpcssProcessId
)
{
ORSTATUS status;
*pcServerSvc = gpSecVals->s_cServerSvc;
*aServerSvc = CopyArray(gpSecVals->s_cServerSvc,gpSecVals->s_aServerSvc,&status);
*pcClientSvc = gpSecVals->s_cClientSvc;
*aClientSvc = CopyArray(gpSecVals->s_cClientSvc,gpSecVals->s_aClientSvc,&status);
if (NULL != gpPingProcess)
{
*pdwRpcssProcessId = gpPingProcess->GetProcessID();
}
else
{
*pdwRpcssProcessId = 0;
}
if (status == OR_OK)
{
*ppdsaOrBindings = (DUALSTRINGARRAY *) MIDL_user_allocate(
gpLocalDSA->wNumEntries * sizeof(WCHAR)
+ sizeof(DUALSTRINGARRAY) );
if (*ppdsaOrBindings)
{
dsaCopy(*ppdsaOrBindings, gpLocalDSA);
}
else
{
status = OR_NOMEM;
}
}
return status;
}
error_status_t ClientResolveOXID(
IN HPROCESS phProcess,
IN OXID *poxidServer,
IN DUALSTRINGARRAY *pssaServerObjectResolverBindings,
IN long fApartment,
OUT OXID_INFO *poxidInfo,
OUT MID *pLocalMidOfRemote)
{
return GetOXID(
phProcess,
*poxidServer,
pssaServerObjectResolverBindings,
fApartment,
0, // wProtseqId not specified
*poxidInfo,
*pLocalMidOfRemote
);
}
error_status_t ServerAllocateOXIDAndOIDs(
IN HPROCESS hProcess,
OUT OXID *poxidServer,
IN long fApartment,
IN unsigned long cOids,
OUT OID aOid[ ],
OUT unsigned long *pcOidsAllocated,
IN OXID_INFO *pOxidInfo,
IN DUALSTRINGARRAY *pdsaStringBindings,
IN DUALSTRINGARRAY *pdsaSecurityBindings)
{
ComDebOut((DEB_OXID, "Calling ServerAllocateOXIDAndOIDs\n"));
ASSERT(pdsaStringBindings != NULL);
if (NULL == pdsaSecurityBindings)
{
pdsaSecurityBindings = (DUALSTRINGARRAY*) &dsaNullBinding;
}
DUALSTRINGARRAY *pdsaMergedBindings;
ORSTATUS status = MergeBindings(
pdsaStringBindings,
pdsaSecurityBindings,
&pdsaMergedBindings
);
if (status != OR_OK) return status;
status = ServerAllocateOXID(
hProcess,
fApartment,
pOxidInfo,
pdsaMergedBindings,
*poxidServer
);
if (status == OR_OK)
{
ComDebOut((DEB_OXID, "Calling ServerAllocateOIDs\n"));
status = ServerAllocateOIDs(
hProcess,
poxidServer,
cOids,
aOid,
pcOidsAllocated
);
}
else
{
ComDebOut((DEB_OXID, "Not Calling ServerAllocateOIDs, status = %d\n",
status));
}
return status;
}
error_status_t ServerAllocateOIDs(
IN HPROCESS hProcess,
IN OXID *poxidServer,
IN unsigned long cOids,
OUT OID aOid[ ],
OUT unsigned long *pcOidsAllocated)
{
ComDebOut((DEB_ITRACE, "Entering ServerAllocateOIDs\n"));
ORSTATUS status;
*pcOidsAllocated = 0;
for (ULONG i = 0; i < cOids; i++)
{
status = ServerAllocateOID(
hProcess,
*poxidServer,
aOid[i]
);
if (status != OR_OK)
{
*pcOidsAllocated = i;
break;
}
else
{
(*pcOidsAllocated)++;
}
}
return status;
}
error_status_t ServerFreeOXIDAndOIDs(
IN HPROCESS hProcess,
IN OXID oxidServer,
IN unsigned long cOids,
IN OID aOids[ ])
{
return ServerFreeOXID(
hProcess,
oxidServer,
cOids,
aOids
);
}
VOID CALLBACK RundownTimerProc(
HWND hwnd, // handle of window for timer messages
UINT uMsg, // WM_TIMER message
UINT idEvent, // timer identifier
DWORD dwTime // current system time
)
{
if (idEvent != IDT_DCOM_RUNDOWN) return; // shouldn't happen -- this is only
// used as callback for one timer
// find the OXID for this thread
COleTls tls;
ASSERT(((OXIDEntry *)tls->pOXIDEntry)->dwTid == GetCurrentThreadId());
ASSERT(((OXIDEntry *)tls->pOXIDEntry)->dwPid == GetCurrentProcessId());
// disable rundown proc if we are inside CoUnitialize(),
// to avoid 16 bit DLLs hang on exit
//
if (tls->dwFlags & OLETLS_THREADUNINITIALIZING)
return;
MOXID Moxid = ((OXIDEntry *)tls->pOXIDEntry)->moxid;
OXID Oxid;
MID Mid;
OXIDFromMOXID(Moxid,&Oxid);
MIDFromMOXID(Moxid,&Mid);
CProtectSharedMemory protector; // locks through rest of lexical scope
COxid *pOxid = gpOxidTable->Lookup(CId2Key(Oxid, Mid));
ASSERT(pOxid);
ComDebOut((DEB_OXID, "Attempting Rundown in apartment OXID = %08x PID = %d\n",
Oxid,GetCurrentProcessId()));
// find the RemUnk for this OXID -- we want only the IRundown interface
IRundown *pRemUnk = tls->pRemoteUnk;
// If there is no RemUnk, nothing is marshalled, so forget about rundown
if (!pRemUnk) return;
ComDebOut((DEB_OXID, "There is a RemUnk for apartment OXID = %08x PID = %d\n",
Oxid,GetCurrentProcessId()));
// go and check your OIDs here
pOxid->RundownOidsIfNecessary(pRemUnk);
}
DWORD _stdcall
RundownThread(void *pInfo)
{
DWORD dwLoopCount = 0;
SRundownThreadInfo *pRundownInfo = (SRundownThreadInfo*)pInfo;
COxid *pSelf = pRundownInfo->pSelf; // store away "this" pointer
BOOL& fKeepRunning = pRundownInfo->fKeepRunning; // and run signal
ASSERT(!IsBadWritePtr(pSelf,sizeof(COxid)));
HRESULT hr = InitChannelIfNecessary(); // initialize thread local storage
if (FAILED(hr)) return OR_INTERNAL_ERROR; // can't run if there is no thread local storage
while (TRUE)
{
::Sleep(RUNDOWN_TIMER_INTERVAL);
CProtectSharedMemory protector; // locks through rest of lexical scope
if (FALSE == fKeepRunning) // we have been told to terminate ourselves
{
PrivMemFree(pRundownInfo);
return OR_OK;
}
dwLoopCount++;
ComDebOut((DEB_OXID, "Attempting Rundown in PID = %d\n",
GetCurrentProcessId()));
IRundown *pRemUnk = gpMTARemoteUnknown;
// If there is no RemUnk, nothing is marshalled, so go back to sleep.
if (!pRemUnk) continue;
ComDebOut((DEB_OXID, "There is a RemUnk for free OXID = %08x PID = %d\n",
pSelf->GetOXID(),GetCurrentProcessId()));
ASSERT(!IsBadWritePtr(pRemUnk,sizeof(CRemoteUnknown)));
pSelf->RundownOidsIfNecessary(pRemUnk);
}
return OR_OK;
}
//
// This variable keeps track of the last time the ping thread woke up.
// If the thread is blocked doing a ping, the time will remain unchanged
// and after the BaseTimeoutInterval the ping thread will be restarted
//
CTime gLastPingTime;
DWORD _stdcall
PingThread(void)
{
DWORD SapCount = SapFreqPerPing - 1;
while (TRUE) // don't use a continue in this loop!
{
BOOL fSappingEnabled = gfSapAdvertiseFailed;
DWORD dwSleepInterval = fSappingEnabled ? BasePingInterval * 1000 / SapFreqPerPing
: BasePingInterval * 1000;
BOOL fPingNow = !fSappingEnabled;
gLastPingTime.SetNow();
if (fSappingEnabled)
{
fPingNow = (++SapCount % SapFreqPerPing == 0);
FakeSapAdvertiseIfNecessary();
}
if (fPingNow)
{
CProtectSharedMemory protector; // locks through rest of scope except where
// temporarily released
ORSTATUS status;
// First do rundown detection -- this may cause deletes from ping sets
COxidTableIterator OxidIter(gpPingProcess->_MyOxids);
for (COxid *pOxid = OxidIter.Next(); pOxid != NULL; pOxid = OxidIter.Next())
{
if (pOxid->HasExpired())
{
// the FALSE signifies that the Oxid does not belong to this thread
gpPingProcess->DisownOxid(pOxid,FALSE);
}
else
{
pOxid->RundownOidsIfNecessary(NULL); // No IRundown param needed
}
}
// Then do pinging
CMidTableIterator MidIter(*gpMidTable);
for (CMid *pMid = MidIter.Next(); pMid != NULL; pMid = MidIter.Next())
{
if (pMid->HasExpired())
{
gpMidTable->Remove(*pMid);
}
else if (!pMid->IsLocal())
{
status = pMid->PingServer();
}
}
// finally, rundown any server-side ping sets that have timed out
CPingSetTableIterator PingIter(gSetTable);
for (CPingSet *pSet = PingIter.Next(); pSet != NULL; pSet = PingIter.Next())
{
if (pSet->HasExpired())
{
// The remove will drop the refcount for the set to 0
// which will call the destructor for the set which will
// call the destructor for the set of COids in it which
// will remove all the COids from that table which will
// drop all their respective ref counts by one as required
gSetTable.Remove(*pSet);
}
}
}
::Sleep(dwSleepInterval); // ping interval is in seconds
}
return OR_OK;
}
error_status_t
ResolveClientOXID(
handle_t hClient,
void *hProcess,
OXID *poxidServer,
DUALSTRINGARRAY *pdsaServerBindings,
LONG fApartment,
USHORT wProtseqId,
OXID_INFO *poxidInfo,
MID *pDestinationMid
)
{
return GetOXID(
(CProcess*)hProcess,
*poxidServer,
pdsaServerBindings,
fApartment,
wProtseqId,
*poxidInfo,
*pDestinationMid,
TRUE // This is a SCM request
);
}
// This function resets the local OR data after RPCSS is launched
void SyncLocalResolverData()
{
CProtectSharedMemory protector; // locks through rest of scope
gpGlobalBlock->ResetGlobals();
}