389 lines
8.8 KiB
C
389 lines
8.8 KiB
C
/****************************************************************************
|
||
*
|
||
* $Archive: S:/STURGEON/SRC/CALLCONT/VCS/Listman.c_v $
|
||
*
|
||
* INTEL Corporation Prorietary Information
|
||
*
|
||
* This listing is supplied under the terms of a license agreement
|
||
* with INTEL Corporation and may not be copied nor disclosed except
|
||
* in accordance with the terms of that agreement.
|
||
*
|
||
* Copyright (c) 1993-1994 Intel Corporation.
|
||
*
|
||
* $Revision: 1.22 $
|
||
* $Date: 22 Jan 1997 14:55:52 $
|
||
* $Author: MANDREWS $
|
||
*
|
||
* Deliverable:
|
||
*
|
||
* Abstract:
|
||
*
|
||
*
|
||
* Notes:
|
||
*
|
||
***************************************************************************/
|
||
|
||
#include "precomp.h"
|
||
|
||
#include "apierror.h"
|
||
#include "incommon.h"
|
||
#include "callcont.h"
|
||
#include "q931.h"
|
||
#include "ccmain.h"
|
||
#include "ccutils.h"
|
||
#include "listman.h"
|
||
|
||
|
||
static BOOL bListenInited = FALSE;
|
||
|
||
static struct {
|
||
PLISTEN pHead;
|
||
LOCK Lock;
|
||
} ListenTable;
|
||
|
||
static struct {
|
||
CC_HLISTEN hListen;
|
||
LOCK Lock;
|
||
} ListenHandle;
|
||
|
||
|
||
HRESULT InitListenManager()
|
||
{
|
||
ASSERT(bListenInited == FALSE);
|
||
|
||
ListenTable.pHead = NULL;
|
||
InitializeLock(&ListenTable.Lock);
|
||
|
||
ListenHandle.hListen = CC_INVALID_HANDLE + 1;
|
||
InitializeLock(&ListenHandle.Lock);
|
||
|
||
bListenInited = TRUE;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DeInitListenManager()
|
||
{
|
||
PLISTEN pListen;
|
||
PLISTEN pNextListen;
|
||
|
||
if (bListenInited == FALSE)
|
||
return CC_OK;
|
||
|
||
pListen = ListenTable.pHead;
|
||
while (pListen != NULL) {
|
||
AcquireLock(&pListen->Lock);
|
||
pNextListen = pListen->pNextInTable;
|
||
FreeListen(pListen);
|
||
pListen = pNextListen;
|
||
}
|
||
|
||
DeleteLock(&ListenHandle.Lock);
|
||
DeleteLock(&ListenTable.Lock);
|
||
bListenInited = FALSE;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT _AddListenToTable( PLISTEN pListen)
|
||
{
|
||
ASSERT(pListen != NULL);
|
||
ASSERT(pListen->hListen != CC_INVALID_HANDLE);
|
||
ASSERT(pListen->bInTable == FALSE);
|
||
|
||
AcquireLock(&ListenTable.Lock);
|
||
|
||
pListen->pNextInTable = ListenTable.pHead;
|
||
pListen->pPrevInTable = NULL;
|
||
if (ListenTable.pHead != NULL)
|
||
ListenTable.pHead->pPrevInTable = pListen;
|
||
ListenTable.pHead = pListen;
|
||
|
||
pListen->bInTable = TRUE;
|
||
|
||
RelinquishLock(&ListenTable.Lock);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT _RemoveListenFromTable( PLISTEN pListen)
|
||
{
|
||
CC_HLISTEN hListen;
|
||
BOOL bTimedOut;
|
||
|
||
ASSERT(pListen != NULL);
|
||
ASSERT(pListen->bInTable == TRUE);
|
||
|
||
// Caller must have a lock on the listen object;
|
||
// in order to avoid deadlock, we must:
|
||
// 1. unlock the listen object,
|
||
// 2. lock the ListenTable,
|
||
// 3. locate the listen object in the ListenTable (note that
|
||
// after step 2, the listen object may be deleted from the
|
||
// ListenTable by another thread),
|
||
// 4. lock the listen object (someone else may have the lock)
|
||
// 5. remove the listen object from the ListenTable,
|
||
// 6. unlock the ListenTable
|
||
//
|
||
// The caller can now safely unlock and destroy the listen object,
|
||
// since no other thread will be able to find the object (its been
|
||
// removed from the ListenTable), and therefore no other thread will
|
||
// be able to lock it.
|
||
|
||
// Save the listen handle; its the only way to look up
|
||
// the listen object in the ListenTable. Note that we
|
||
// can't use pListen to find the listen object, since
|
||
// pListen may be free'd up, and another listen object
|
||
// allocated at the same address
|
||
hListen = pListen->hListen;
|
||
|
||
// step 1
|
||
RelinquishLock(&pListen->Lock);
|
||
|
||
step2:
|
||
// step 2
|
||
AcquireLock(&ListenTable.Lock);
|
||
|
||
// step 3
|
||
pListen = ListenTable.pHead;
|
||
while ((pListen != NULL) && (pListen->hListen != hListen))
|
||
pListen = pListen->pNextInTable;
|
||
|
||
if (pListen != NULL) {
|
||
// step 4
|
||
AcquireTimedLock(&pListen->Lock,10,&bTimedOut);
|
||
if (bTimedOut) {
|
||
RelinquishLock(&ListenTable.Lock);
|
||
Sleep(0);
|
||
goto step2;
|
||
}
|
||
// step 5
|
||
if (pListen->pPrevInTable == NULL)
|
||
ListenTable.pHead = pListen->pNextInTable;
|
||
else
|
||
pListen->pPrevInTable->pNextInTable = pListen->pNextInTable;
|
||
|
||
if (pListen->pNextInTable != NULL)
|
||
pListen->pNextInTable->pPrevInTable = pListen->pPrevInTable;
|
||
|
||
pListen->pNextInTable = NULL;
|
||
pListen->pPrevInTable = NULL;
|
||
pListen->bInTable = FALSE;
|
||
}
|
||
|
||
// step 6
|
||
RelinquishLock(&ListenTable.Lock);
|
||
|
||
if (pListen == NULL)
|
||
return CC_BAD_PARAM;
|
||
else
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT _MakeListenHandle( PCC_HLISTEN phListen)
|
||
{
|
||
AcquireLock(&ListenHandle.Lock);
|
||
*phListen = ListenHandle.hListen++;
|
||
RelinquishLock(&ListenHandle.Lock);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT AllocAndLockListen( PCC_HLISTEN phListen,
|
||
PCC_ADDR pListenAddr,
|
||
HQ931LISTEN hQ931Listen,
|
||
PCC_ALIASNAMES pLocalAliasNames,
|
||
DWORD_PTR dwListenToken,
|
||
CC_LISTEN_CALLBACK ListenCallback,
|
||
PPLISTEN ppListen)
|
||
{
|
||
HRESULT status;
|
||
|
||
ASSERT(bListenInited == TRUE);
|
||
|
||
// all parameters should have been validated by the caller
|
||
ASSERT(phListen != NULL);
|
||
ASSERT(pListenAddr != NULL);
|
||
ASSERT(ListenCallback != NULL);
|
||
ASSERT(ppListen != NULL);
|
||
|
||
// set phListen now, in case we encounter an error
|
||
*phListen = CC_INVALID_HANDLE;
|
||
|
||
*ppListen = (PLISTEN)MemAlloc(sizeof(LISTEN));
|
||
if (*ppListen == NULL)
|
||
return CC_NO_MEMORY;
|
||
|
||
(*ppListen)->bInTable = FALSE;
|
||
status = _MakeListenHandle(&(*ppListen)->hListen);
|
||
if (status != CC_OK) {
|
||
MemFree(*ppListen);
|
||
return status;
|
||
}
|
||
|
||
// make a local copy of the ListenAddr
|
||
(*ppListen)->ListenAddr = *pListenAddr;
|
||
(*ppListen)->hQ931Listen = hQ931Listen;
|
||
(*ppListen)->dwListenToken = dwListenToken;
|
||
(*ppListen)->pLocalAliasNames = NULL;
|
||
(*ppListen)->ListenCallback = ListenCallback;
|
||
(*ppListen)->pNextInTable = NULL;
|
||
(*ppListen)->pPrevInTable = NULL;
|
||
(*ppListen)->pLocalAliasNames = NULL;
|
||
|
||
InitializeLock(&(*ppListen)->Lock);
|
||
AcquireLock(&(*ppListen)->Lock);
|
||
|
||
*phListen = (*ppListen)->hListen;
|
||
|
||
// make a local copy of the local alias names
|
||
status = Q931CopyAliasNames(&(*ppListen)->pLocalAliasNames, pLocalAliasNames);
|
||
if (status != CS_OK) {
|
||
FreeListen(*ppListen);
|
||
*phListen = CC_INVALID_HANDLE;
|
||
return status;
|
||
}
|
||
|
||
// add the Listen to the Listen table
|
||
status = _AddListenToTable(*ppListen);
|
||
if (status != CC_OK)
|
||
FreeListen(*ppListen);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
// Caller must have a lock on the Listen object
|
||
HRESULT FreeListen( PLISTEN pListen)
|
||
{
|
||
CC_HLISTEN hListen;
|
||
|
||
ASSERT(pListen != NULL);
|
||
|
||
// caller must have a lock on the Listen object,
|
||
// so there's no need to re-lock it
|
||
|
||
hListen = pListen->hListen;
|
||
|
||
if (pListen->bInTable == TRUE)
|
||
if (_RemoveListenFromTable(pListen) == CC_BAD_PARAM)
|
||
// the Listen object was deleted by another thread,
|
||
// so just return CC_OK
|
||
return CC_OK;
|
||
|
||
if (pListen->pLocalAliasNames != NULL)
|
||
Q931FreeAliasNames(pListen->pLocalAliasNames);
|
||
|
||
// Since the listen object has been removed from the ListenTable,
|
||
// no other thread will be able to find the listen object and obtain
|
||
// a lock, so its safe to unlock the listen object and delete it here
|
||
RelinquishLock(&pListen->Lock);
|
||
DeleteLock(&pListen->Lock);
|
||
MemFree(pListen);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT LockListen( CC_HLISTEN hListen,
|
||
PPLISTEN ppListen)
|
||
{
|
||
BOOL bTimedOut;
|
||
|
||
ASSERT(hListen != CC_INVALID_HANDLE);
|
||
ASSERT(ppListen != NULL);
|
||
|
||
step1:
|
||
AcquireLock(&ListenTable.Lock);
|
||
|
||
*ppListen = ListenTable.pHead;
|
||
while ((*ppListen != NULL) && ((*ppListen)->hListen != hListen))
|
||
*ppListen = (*ppListen)->pNextInTable;
|
||
|
||
if (*ppListen != NULL) {
|
||
AcquireTimedLock(&(*ppListen)->Lock,10,&bTimedOut);
|
||
if (bTimedOut) {
|
||
RelinquishLock(&ListenTable.Lock);
|
||
Sleep(0);
|
||
goto step1;
|
||
}
|
||
}
|
||
|
||
RelinquishLock(&ListenTable.Lock);
|
||
|
||
if (*ppListen == NULL)
|
||
return CC_BAD_PARAM;
|
||
else
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateListen( CC_HLISTEN hListen)
|
||
{
|
||
PLISTEN pListen;
|
||
|
||
ASSERT(hListen != CC_INVALID_HANDLE);
|
||
|
||
AcquireLock(&ListenTable.Lock);
|
||
|
||
pListen = ListenTable.pHead;
|
||
while ((pListen != NULL) && (pListen->hListen != hListen))
|
||
pListen = pListen->pNextInTable;
|
||
|
||
RelinquishLock(&ListenTable.Lock);
|
||
|
||
if (pListen == NULL)
|
||
return CC_BAD_PARAM;
|
||
else
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT UnlockListen( PLISTEN pListen)
|
||
{
|
||
ASSERT(pListen != NULL);
|
||
|
||
RelinquishLock(&pListen->Lock);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT GetLastListenAddress( PCC_ADDR pListenAddr)
|
||
{
|
||
HRESULT status;
|
||
PLISTEN pListen;
|
||
PLISTEN pLastListen;
|
||
|
||
ASSERT(pListenAddr != NULL);
|
||
|
||
AcquireLock(&ListenTable.Lock);
|
||
|
||
pListen = ListenTable.pHead;
|
||
pLastListen = pListen;
|
||
while (pListen != NULL) {
|
||
if (pLastListen->hListen < pListen->hListen)
|
||
pLastListen = pListen;
|
||
pListen = pListen->pNextInTable;
|
||
}
|
||
|
||
if (pLastListen == NULL)
|
||
status = CC_BAD_PARAM;
|
||
else {
|
||
status = CC_OK;
|
||
*pListenAddr = pLastListen->ListenAddr;
|
||
}
|
||
|
||
RelinquishLock(&ListenTable.Lock);
|
||
return status;
|
||
}
|
||
|