|
|
/****************************************************************************
* * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/chanman.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.43 $ * $Date: 04 Mar 1997 17:35:04 $ * $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"
#include "q931man.h"
#include "userman.h"
#include "callman.h"
#include "confman.h"
#include "chanman.h"
static BOOL bChannelInited = FALSE;
static struct { PCHANNEL pHead; LOCK Lock; } ChannelTable;
static struct { CC_HCHANNEL hChannel; LOCK Lock; } ChannelHandle;
HRESULT InitChannelManager() { ASSERT(bChannelInited == FALSE);
ChannelTable.pHead = NULL; InitializeLock(&ChannelTable.Lock);
ChannelHandle.hChannel = CC_INVALID_HANDLE + 1; InitializeLock(&ChannelHandle.Lock);
bChannelInited = TRUE; return CC_OK; }
HRESULT DeInitChannelManager() { PCHANNEL pChannel; PCHANNEL pNextChannel;
if (bChannelInited == FALSE) return CC_OK;
pChannel = ChannelTable.pHead; while (pChannel != NULL) { AcquireLock(&pChannel->Lock); pNextChannel = pChannel->pNextInTable; FreeChannel(pChannel); pChannel = pNextChannel; }
DeleteLock(&ChannelHandle.Lock); DeleteLock(&ChannelTable.Lock); bChannelInited = FALSE; return CC_OK; }
HRESULT _AddChannelToTable( PCHANNEL pChannel) { ASSERT(pChannel != NULL); ASSERT(pChannel->hChannel != CC_INVALID_HANDLE); ASSERT(pChannel->bInTable == FALSE);
AcquireLock(&ChannelTable.Lock);
pChannel->pNextInTable = ChannelTable.pHead; pChannel->pPrevInTable = NULL; if (ChannelTable.pHead != NULL) ChannelTable.pHead->pPrevInTable = pChannel; ChannelTable.pHead = pChannel;
pChannel->bInTable = TRUE;
RelinquishLock(&ChannelTable.Lock); return CC_OK; }
HRESULT _RemoveChannelFromTable( PCHANNEL pChannel) { CC_HCHANNEL hChannel; BOOL bTimedOut;
ASSERT(pChannel != NULL); ASSERT(pChannel->bInTable == TRUE);
// Caller must have a lock on the channel object;
// in order to avoid deadlock, we must:
// 1. unlock the channel object,
// 2. lock the ChannelTable,
// 3. locate the channel object in the ChannelTable (note that
// after step 2, the channel object may be deleted from the
// ChannelTable by another thread),
// 4. lock the channel object (someone else may have the lock)
// 5. remove the channel object from the ChannelTable,
// 6. unlock the ChannelTable
//
// The caller can now safely unlock and destroy the channel object,
// since no other thread will be able to find the object (its been
// removed from the ChannelTable), and therefore no other thread will
// be able to lock it.
// Save the channel handle; its the only way to look up
// the channel object in the ChannelTable. Note that we
// can't use pChannel to find the channel object, since
// pChannel may be free'd up, and another channel object
// allocated at the same address
hChannel = pChannel->hChannel;
// step 1
RelinquishLock(&pChannel->Lock);
step2: // step 2
AcquireLock(&ChannelTable.Lock);
// step 3
pChannel = ChannelTable.pHead; while ((pChannel != NULL) && (pChannel->hChannel != hChannel)) pChannel = pChannel->pNextInTable;
if (pChannel != NULL) { // step 4
AcquireTimedLock(&pChannel->Lock,10,&bTimedOut); if (bTimedOut) { RelinquishLock(&ChannelTable.Lock); Sleep(0); goto step2; } // step 5
if (pChannel->pPrevInTable == NULL) ChannelTable.pHead = pChannel->pNextInTable; else pChannel->pPrevInTable->pNextInTable = pChannel->pNextInTable;
if (pChannel->pNextInTable != NULL) pChannel->pNextInTable->pPrevInTable = pChannel->pPrevInTable;
pChannel->pPrevInTable = NULL; pChannel->pNextInTable = NULL; pChannel->bInTable = FALSE; }
// step 6
RelinquishLock(&ChannelTable.Lock);
if (pChannel == NULL) return CC_BAD_PARAM; else return CC_OK; }
HRESULT _MakeChannelHandle( PCC_HCHANNEL phChannel) { AcquireLock(&ChannelHandle.Lock); *phChannel = ChannelHandle.hChannel++; RelinquishLock(&ChannelHandle.Lock); return CC_OK; }
HRESULT AllocAndLockChannel( PCC_HCHANNEL phChannel, PCONFERENCE pConference, CC_HCALL hCall, PCC_TERMCAP pTxTermCap, PCC_TERMCAP pRxTermCap, H245_MUX_T *pTxMuxTable, H245_MUX_T *pRxMuxTable, H245_ACCESS_T *pSeparateStack, DWORD_PTR dwUserToken, BYTE bChannelType, BYTE bSessionID, BYTE bAssociatedSessionID, WORD wRemoteChannelNumber, PCC_ADDR pLocalRTPAddr, PCC_ADDR pLocalRTCPAddr, PCC_ADDR pPeerRTPAddr, PCC_ADDR pPeerRTCPAddr, BOOL bLocallyOpened, PPCHANNEL ppChannel) { HRESULT status; ASSERT(bChannelInited == TRUE);
// all parameters should have been validated by the caller
ASSERT(phChannel != NULL); ASSERT(pConference != NULL); ASSERT((bChannelType == TX_CHANNEL) || (bChannelType == RX_CHANNEL) || (bChannelType == TXRX_CHANNEL) || (bChannelType == PROXY_CHANNEL)); ASSERT(ppChannel != NULL);
// set phChannel now, in case we encounter an error
*phChannel = CC_INVALID_HANDLE;
*ppChannel = (PCHANNEL)MemAlloc(sizeof(CHANNEL)); if (*ppChannel == NULL) return CC_NO_MEMORY;
(*ppChannel)->bInTable = FALSE; (*ppChannel)->bMultipointChannel = FALSE; (*ppChannel)->hCall = hCall; (*ppChannel)->wNumOutstandingRequests = 0; (*ppChannel)->pTxH245TermCap = NULL; (*ppChannel)->pRxH245TermCap = NULL; (*ppChannel)->pTxMuxTable = NULL; (*ppChannel)->pRxMuxTable = NULL; (*ppChannel)->pSeparateStack = NULL; (*ppChannel)->pCloseRequests = NULL; (*ppChannel)->pLocalRTPAddr = NULL; (*ppChannel)->pLocalRTCPAddr = NULL; (*ppChannel)->pPeerRTPAddr = NULL; (*ppChannel)->pPeerRTCPAddr = NULL; (*ppChannel)->dwUserToken = dwUserToken; (*ppChannel)->hConference = pConference->hConference; (*ppChannel)->bSessionID = bSessionID; (*ppChannel)->bAssociatedSessionID = bAssociatedSessionID; (*ppChannel)->wLocalChannelNumber = 0; (*ppChannel)->wRemoteChannelNumber = 0; (*ppChannel)->bLocallyOpened = bLocallyOpened; (*ppChannel)->pNextInTable = NULL; (*ppChannel)->pPrevInTable = NULL; (*ppChannel)->pNext = NULL; (*ppChannel)->pPrev = NULL; InitializeLock(&(*ppChannel)->Lock); AcquireLock(&(*ppChannel)->Lock);
status = _MakeChannelHandle(&(*ppChannel)->hChannel); if (status != CC_OK) { FreeChannel(*ppChannel); return status; }
if (bLocallyOpened == TRUE) (*ppChannel)->tsAccepted = TS_TRUE; else (*ppChannel)->tsAccepted = TS_UNKNOWN;
if (pTxMuxTable != NULL) { (*ppChannel)->pTxMuxTable = (H245_MUX_T *)MemAlloc(sizeof(H245_MUX_T)); if ((*ppChannel)->pTxMuxTable == NULL) { FreeChannel(*ppChannel); return CC_NO_MEMORY; } *(*ppChannel)->pTxMuxTable = *pTxMuxTable; }
if (pRxMuxTable != NULL) { (*ppChannel)->pRxMuxTable = (H245_MUX_T *)MemAlloc(sizeof(H245_MUX_T)); if ((*ppChannel)->pRxMuxTable == NULL) { FreeChannel(*ppChannel); return CC_NO_MEMORY; } *(*ppChannel)->pRxMuxTable = *pRxMuxTable; }
if (pSeparateStack != NULL) { status = CopySeparateStack(&(*ppChannel)->pSeparateStack, pSeparateStack); if (status != CC_OK) { FreeChannel(*ppChannel); return status; } }
(*ppChannel)->bChannelType = bChannelType; (*ppChannel)->bCallbackInvoked = FALSE; if (pTxTermCap != NULL) { status = H245CopyCap(&(*ppChannel)->pTxH245TermCap, pTxTermCap); if (status != H245_ERROR_OK) { FreeChannel(*ppChannel); return status; } } if (pRxTermCap != NULL) { status = H245CopyCap(&(*ppChannel)->pRxH245TermCap, pRxTermCap); if (status != H245_ERROR_OK) { FreeChannel(*ppChannel); return status; } } if (pLocalRTPAddr != NULL) { (*ppChannel)->pLocalRTPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if ((*ppChannel)->pLocalRTPAddr == NULL) { FreeChannel(*ppChannel); return CC_NO_MEMORY; } *(*ppChannel)->pLocalRTPAddr = *pLocalRTPAddr; } if (pLocalRTCPAddr != NULL) { (*ppChannel)->pLocalRTCPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if ((*ppChannel)->pLocalRTCPAddr == NULL) { FreeChannel(*ppChannel); return CC_NO_MEMORY; } *(*ppChannel)->pLocalRTCPAddr = *pLocalRTCPAddr; } if (pPeerRTPAddr != NULL) { (*ppChannel)->pPeerRTPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if ((*ppChannel)->pPeerRTPAddr == NULL) { FreeChannel(*ppChannel); return CC_NO_MEMORY; } *(*ppChannel)->pPeerRTPAddr = *pPeerRTPAddr; } if (pPeerRTCPAddr != NULL) { (*ppChannel)->pPeerRTCPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if ((*ppChannel)->pPeerRTCPAddr == NULL) { FreeChannel(*ppChannel); return CC_NO_MEMORY; } *(*ppChannel)->pPeerRTCPAddr = *pPeerRTCPAddr; } *phChannel = (*ppChannel)->hChannel;
// add the conference to the conference table
status = _AddChannelToTable(*ppChannel); if (status != CC_OK) { FreeChannel(*ppChannel); return status; }
switch (bChannelType) { case TX_CHANNEL: status = AllocateChannelNumber(pConference, &(*ppChannel)->wLocalChannelNumber); if (status != CC_OK) { FreeChannel(*ppChannel); return status; } (*ppChannel)->wRemoteChannelNumber = 0; break;
case RX_CHANNEL: (*ppChannel)->wLocalChannelNumber = 0; (*ppChannel)->wRemoteChannelNumber = wRemoteChannelNumber; break;
case TXRX_CHANNEL: status = AllocateChannelNumber(pConference, &(*ppChannel)->wLocalChannelNumber); if (status != CC_OK) { FreeChannel(*ppChannel); return status; } if (bLocallyOpened) (*ppChannel)->wRemoteChannelNumber = 0; else (*ppChannel)->wRemoteChannelNumber = wRemoteChannelNumber; break;
case PROXY_CHANNEL: status = AllocateChannelNumber(pConference, &(*ppChannel)->wLocalChannelNumber); if (status != CC_OK) { FreeChannel(*ppChannel); return status; } (*ppChannel)->wRemoteChannelNumber = wRemoteChannelNumber; break;
default: ASSERT(0); break; } return CC_OK; }
HRESULT AddLocalAddrPairToChannel( PCC_ADDR pRTPAddr, PCC_ADDR pRTCPAddr, PCHANNEL pChannel) { ASSERT(pChannel != NULL);
if (pRTPAddr != NULL) { if (pChannel->pLocalRTPAddr == NULL) { pChannel->pLocalRTPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pChannel->pLocalRTPAddr == NULL) return CC_NO_MEMORY; } *pChannel->pLocalRTPAddr = *pRTPAddr; }
if (pRTCPAddr != NULL) { if (pChannel->pLocalRTCPAddr == NULL) { pChannel->pLocalRTCPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pChannel->pLocalRTCPAddr == NULL) return CC_NO_MEMORY; } *pChannel->pLocalRTCPAddr = *pRTCPAddr; }
return CC_OK; }
HRESULT AddSeparateStackToChannel( H245_ACCESS_T *pSeparateStack, PCHANNEL pChannel) { ASSERT(pSeparateStack != NULL); ASSERT(pChannel != NULL);
if (pChannel->pSeparateStack != NULL) return CC_BAD_PARAM;
pChannel->pSeparateStack = (H245_ACCESS_T *)MemAlloc(sizeof(H245_ACCESS_T)); if (pChannel->pSeparateStack == NULL) return CC_NO_MEMORY; *pChannel->pSeparateStack = *pSeparateStack; return CC_OK; }
// Caller must have a lock on the channel object
HRESULT FreeChannel( PCHANNEL pChannel) { HRESULT status; CC_HCHANNEL hChannel; PCONFERENCE pConference;
ASSERT(pChannel != NULL);
// caller must have a lock on the channel object,
// so there's no need to re-lock it
hChannel = pChannel->hChannel; if (pChannel->hConference != CC_INVALID_HANDLE) { UnlockChannel(pChannel); status = LockChannelAndConference(hChannel, &pChannel, &pConference); if (status != CC_OK) return status; }
if (pChannel->bInTable == TRUE) if (_RemoveChannelFromTable(pChannel) == CC_BAD_PARAM) // the channel object was deleted by another thread,
// so just return CC_OK
return CC_OK;
if (pChannel->hConference != CC_INVALID_HANDLE) RemoveChannelFromConference(pChannel, pConference);
if (pChannel->pSeparateStack != NULL) FreeSeparateStack(pChannel->pSeparateStack);
if (pChannel->pTxMuxTable != NULL) MemFree(pChannel->pTxMuxTable);
if (pChannel->pRxMuxTable != NULL) MemFree(pChannel->pRxMuxTable);
if (pChannel->pTxH245TermCap != NULL) H245FreeCap(pChannel->pTxH245TermCap);
if (pChannel->pRxH245TermCap != NULL) H245FreeCap(pChannel->pRxH245TermCap);
while (DequeueRequest(&pChannel->pCloseRequests, NULL) == CC_OK);
if (pChannel->pLocalRTPAddr != NULL) MemFree(pChannel->pLocalRTPAddr);
if (pChannel->pLocalRTCPAddr != NULL) MemFree(pChannel->pLocalRTCPAddr);
if (pChannel->pPeerRTPAddr != NULL) MemFree(pChannel->pPeerRTPAddr);
if (pChannel->pPeerRTCPAddr != NULL) MemFree(pChannel->pPeerRTCPAddr);
if (pChannel->wLocalChannelNumber != 0) { FreeChannelNumber(pConference, pChannel->wLocalChannelNumber); }
if (pChannel->hConference != CC_INVALID_HANDLE) UnlockConference(pConference);
// Since the channel object has been removed from the ChannelTable,
// no other thread will be able to find the channel object and obtain
// a lock, so its safe to unlock the channel object and delete it here
RelinquishLock(&pChannel->Lock); DeleteLock(&pChannel->Lock); MemFree(pChannel); return CC_OK; }
HRESULT LockChannel( CC_HCHANNEL hChannel, PPCHANNEL ppChannel) { BOOL bTimedOut;
ASSERT(hChannel != CC_INVALID_HANDLE); ASSERT(ppChannel != NULL);
step1: AcquireLock(&ChannelTable.Lock);
*ppChannel = ChannelTable.pHead; while ((*ppChannel != NULL) && ((*ppChannel)->hChannel != hChannel)) *ppChannel = (*ppChannel)->pNextInTable;
if (*ppChannel != NULL) { AcquireTimedLock(&(*ppChannel)->Lock,10,&bTimedOut); if (bTimedOut) { RelinquishLock(&ChannelTable.Lock); Sleep(0); goto step1; } }
RelinquishLock(&ChannelTable.Lock);
if (*ppChannel == NULL) return CC_BAD_PARAM; else return CC_OK; }
HRESULT LockChannelAndConference( CC_HCHANNEL hChannel, PPCHANNEL ppChannel, PPCONFERENCE ppConference) { HRESULT status; CC_HCONFERENCE hConference;
ASSERT(hChannel != CC_INVALID_HANDLE); ASSERT(ppChannel != NULL); ASSERT(ppConference != NULL);
status = LockChannel(hChannel, ppChannel); if (status != CC_OK) return status; if ((*ppChannel)->hConference == CC_INVALID_HANDLE) { UnlockChannel(*ppChannel); return CC_BAD_PARAM; }
hConference = (*ppChannel)->hConference; UnlockChannel(*ppChannel);
status = LockConference(hConference, ppConference); if (status != CC_OK) return status;
status = LockChannel(hChannel, ppChannel); if (status != CC_OK) { UnlockConference(*ppConference); return status; } return CC_OK; }
HRESULT ValidateChannel( CC_HCHANNEL hChannel) { PCHANNEL pChannel;
ASSERT(hChannel != CC_INVALID_HANDLE);
AcquireLock(&ChannelTable.Lock);
pChannel = ChannelTable.pHead; while ((pChannel != NULL) && (pChannel->hChannel != hChannel)) pChannel = pChannel->pNextInTable;
RelinquishLock(&ChannelTable.Lock);
if (pChannel == NULL) return CC_BAD_PARAM; else return CC_OK; }
HRESULT UnlockChannel( PCHANNEL pChannel) { ASSERT(pChannel != NULL);
RelinquishLock(&pChannel->Lock); return CC_OK; }
|