windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/callcont/chanman.c
2020-09-26 16:20:57 +08:00

638 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
*
* $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;
}