2804 lines
79 KiB
C
2804 lines
79 KiB
C
/****************************************************************************
|
||
*
|
||
* $Archive: S:/STURGEON/SRC/CALLCONT/VCS/ccutils.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.107 $
|
||
* $Date: 04 Mar 1997 17:34:44 $
|
||
* $Author: MANDREWS $
|
||
*
|
||
* Deliverable:
|
||
*
|
||
* Abstract:
|
||
*
|
||
*
|
||
* Notes:
|
||
*
|
||
***************************************************************************/
|
||
|
||
#include "precomp.h"
|
||
|
||
#include "incommon.h"
|
||
#include "callcont.h"
|
||
#include "q931.h"
|
||
#include "apierror.h"
|
||
#include "ccmain.h"
|
||
#include "chanman.h"
|
||
#include "confman.h"
|
||
#include "callman.h"
|
||
#include "q931man.h"
|
||
#include "userman.h"
|
||
#include "ccutils.h"
|
||
#include "linkapi.h"
|
||
#include "h245man.h"
|
||
|
||
extern CC_CONFERENCEID InvalidConferenceID;
|
||
|
||
|
||
|
||
HANDLE ghCCLock = NULL;
|
||
HRESULT InitializeCCLock(VOID)
|
||
{
|
||
ASSERT(ghCCLock == NULL);
|
||
ghCCLock = CreateMutex(NULL, FALSE, NULL);
|
||
if(ghCCLock == NULL)
|
||
{
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
else
|
||
{
|
||
return CC_OK;
|
||
}
|
||
}
|
||
VOID UnInitializeCCLock()
|
||
{
|
||
ASSERT(ghCCLock);
|
||
if(ghCCLock)
|
||
{
|
||
CloseHandle(ghCCLock);
|
||
}
|
||
}
|
||
|
||
VOID CCLOCK_AcquireLock()
|
||
{
|
||
DWORD dwStatus;
|
||
ASSERT(ghCCLock);
|
||
dwStatus = WaitForSingleObject(ghCCLock, INFINITE);
|
||
|
||
if ((dwStatus != WAIT_OBJECT_0) && (dwStatus != WAIT_TIMEOUT))
|
||
{
|
||
ASSERT(0);
|
||
}
|
||
}
|
||
|
||
VOID CCLOCK_RelinquishLock()
|
||
{
|
||
ASSERT(ghCCLock);
|
||
ReleaseMutex(ghCCLock);
|
||
}
|
||
|
||
HRESULT InitializeLock( PLOCK pLock)
|
||
{
|
||
ASSERT(pLock != NULL);
|
||
|
||
#ifdef _DEBUG
|
||
InitializeCriticalSection(&pLock->LockInfoLock);
|
||
pLock->wLockCount = 0;
|
||
pLock->wNumQueuedThreads = 0;
|
||
pLock->hOwningThread = 0;
|
||
#endif
|
||
|
||
pLock->Lock = CreateMutex(NULL, // security attributes
|
||
FALSE, // initial owner
|
||
NULL); // name
|
||
|
||
if (pLock->Lock == NULL) {
|
||
#ifdef _DEBUG
|
||
DeleteCriticalSection(&pLock->LockInfoLock);
|
||
#endif
|
||
return CC_INTERNAL_ERROR;
|
||
} else
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DeleteLock( PLOCK pLock)
|
||
{
|
||
ASSERT(pLock != NULL);
|
||
|
||
#ifdef _DEBUG
|
||
DeleteCriticalSection(&pLock->LockInfoLock);
|
||
#endif
|
||
|
||
if (CloseHandle(pLock->Lock) == TRUE)
|
||
return CC_OK;
|
||
else
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
|
||
|
||
HRESULT AcquireLock( PLOCK pLock)
|
||
{
|
||
HRESULT status;
|
||
|
||
ASSERT(pLock != NULL);
|
||
|
||
status = AcquireTimedLock(pLock, INFINITE, NULL);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT AcquireTimedLock( PLOCK pLock,
|
||
DWORD dwTimeout,
|
||
BOOL *pbTimedOut)
|
||
{
|
||
DWORD dwStatus;
|
||
|
||
ASSERT(pLock != NULL);
|
||
|
||
#ifdef _DEBUG
|
||
EnterCriticalSection(&pLock->LockInfoLock);
|
||
(pLock->wNumQueuedThreads)++;
|
||
LeaveCriticalSection(&pLock->LockInfoLock);
|
||
#endif
|
||
|
||
dwStatus = WaitForSingleObject(pLock->Lock, dwTimeout);
|
||
|
||
#ifdef _DEBUG
|
||
EnterCriticalSection(&pLock->LockInfoLock);
|
||
(pLock->wNumQueuedThreads)--;
|
||
(pLock->wLockCount)++;
|
||
pLock->hOwningThread = GetCurrentThread();
|
||
LeaveCriticalSection(&pLock->LockInfoLock);
|
||
#endif
|
||
|
||
if ((dwStatus != WAIT_OBJECT_0) && (dwStatus != WAIT_TIMEOUT))
|
||
return CC_INTERNAL_ERROR;
|
||
|
||
if (dwStatus == WAIT_TIMEOUT) {
|
||
if (pbTimedOut != NULL) {
|
||
*pbTimedOut = TRUE;
|
||
}
|
||
} else {
|
||
if (pbTimedOut != NULL) {
|
||
*pbTimedOut = FALSE;
|
||
}
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT RelinquishLock( PLOCK pLock)
|
||
{
|
||
ASSERT(pLock != NULL);
|
||
|
||
#ifdef _DEBUG
|
||
EnterCriticalSection(&pLock->LockInfoLock);
|
||
(pLock->wLockCount)--;
|
||
if (pLock->wLockCount == 0)
|
||
pLock->hOwningThread = 0;
|
||
LeaveCriticalSection(&pLock->LockInfoLock);
|
||
#endif
|
||
|
||
if (ReleaseMutex(pLock->Lock) == TRUE)
|
||
return CC_OK;
|
||
else
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateOctetString( PCC_OCTETSTRING pOctetString)
|
||
{
|
||
if (pOctetString == NULL)
|
||
return CC_OK;
|
||
if ((pOctetString->wOctetStringLength > 0) &&
|
||
(pOctetString->pOctetString == NULL))
|
||
return CC_BAD_PARAM;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyOctetString( PCC_OCTETSTRING *ppDest,
|
||
PCC_OCTETSTRING pSource)
|
||
{
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
*ppDest = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
(*ppDest)->wOctetStringLength = pSource->wOctetStringLength;
|
||
if ((pSource->wOctetStringLength == 0) ||
|
||
(pSource->pOctetString == NULL)) {
|
||
pSource->wOctetStringLength = 0;
|
||
(*ppDest)->pOctetString = NULL;
|
||
} else {
|
||
(*ppDest)->pOctetString = (BYTE *)MemAlloc(pSource->wOctetStringLength);
|
||
if ((*ppDest)->pOctetString == NULL) {
|
||
MemFree(*ppDest);
|
||
*ppDest = NULL;
|
||
return CC_NO_MEMORY;
|
||
}
|
||
memcpy((*ppDest)->pOctetString, pSource->pOctetString, pSource->wOctetStringLength);
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeOctetString( PCC_OCTETSTRING pOctetString)
|
||
{
|
||
if (pOctetString == NULL)
|
||
return CC_OK;
|
||
if ((pOctetString->wOctetStringLength > 0) &&
|
||
(pOctetString->pOctetString != NULL))
|
||
MemFree(pOctetString->pOctetString);
|
||
MemFree(pOctetString);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopySeparateStack( H245_ACCESS_T **ppDest,
|
||
H245_ACCESS_T *pSource)
|
||
{
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
// We currently can't handle IP source route addresses,
|
||
// since this address format contains embedded pointers
|
||
// that cannot simply be copied
|
||
if ((pSource->networkAddress.choice == localAreaAddress_chosen) &&
|
||
(pSource->networkAddress.u.localAreaAddress.choice == unicastAddress_chosen) &&
|
||
(pSource->networkAddress.u.localAreaAddress.u.unicastAddress.choice == iPSourceRouteAddress_chosen))
|
||
return CC_NOT_IMPLEMENTED;
|
||
|
||
*ppDest = (H245_ACCESS_T *)MemAlloc(sizeof(H245_ACCESS_T));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
|
||
**ppDest = *pSource;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeSeparateStack( H245_ACCESS_T *pSeparateStack)
|
||
{
|
||
if (pSeparateStack == NULL)
|
||
return CC_OK;
|
||
MemFree(pSeparateStack);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateNonStandardData( PCC_NONSTANDARDDATA pNonStandardData)
|
||
{
|
||
if (pNonStandardData == NULL)
|
||
return CC_OK;
|
||
return ValidateOctetString(&pNonStandardData->sData);
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyNonStandardData( PCC_NONSTANDARDDATA *ppDest,
|
||
PCC_NONSTANDARDDATA pSource)
|
||
{
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
*ppDest = (PCC_NONSTANDARDDATA)MemAlloc(sizeof(CC_NONSTANDARDDATA));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
**ppDest = *pSource;
|
||
if ((pSource->sData.wOctetStringLength == 0) ||
|
||
(pSource->sData.pOctetString == NULL)) {
|
||
(*ppDest)->sData.wOctetStringLength = 0;
|
||
(*ppDest)->sData.pOctetString = NULL;
|
||
} else {
|
||
(*ppDest)->sData.pOctetString = (BYTE *)MemAlloc(pSource->sData.wOctetStringLength);
|
||
if ((*ppDest)->sData.pOctetString == NULL) {
|
||
MemFree(*ppDest);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
memcpy((*ppDest)->sData.pOctetString,
|
||
pSource->sData.pOctetString,
|
||
pSource->sData.wOctetStringLength);
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeNonStandardData( PCC_NONSTANDARDDATA pNonStandardData)
|
||
{
|
||
if (pNonStandardData == NULL)
|
||
return CC_OK;
|
||
if ((pNonStandardData->sData.wOctetStringLength > 0) &&
|
||
(pNonStandardData->sData.pOctetString != NULL))
|
||
MemFree(pNonStandardData->sData.pOctetString);
|
||
MemFree(pNonStandardData);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateVendorInfo( PCC_VENDORINFO pVendorInfo)
|
||
{
|
||
HRESULT status;
|
||
|
||
if (pVendorInfo == NULL)
|
||
return CC_OK;
|
||
status = ValidateOctetString(pVendorInfo->pProductNumber);
|
||
if (status != CC_OK)
|
||
return status;
|
||
status = ValidateOctetString(pVendorInfo->pVersionNumber);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyVendorInfo( PCC_VENDORINFO *ppDest,
|
||
PCC_VENDORINFO pSource)
|
||
{
|
||
HRESULT status;
|
||
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
*ppDest = (PCC_VENDORINFO)MemAlloc(sizeof(CC_VENDORINFO));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
**ppDest = *pSource;
|
||
status = CopyOctetString(&(*ppDest)->pProductNumber, pSource->pProductNumber);
|
||
if (status != CC_OK) {
|
||
MemFree(*ppDest);
|
||
return status;
|
||
}
|
||
status = CopyOctetString(&(*ppDest)->pVersionNumber, pSource->pVersionNumber);
|
||
if (status != CC_OK) {
|
||
FreeOctetString((*ppDest)->pProductNumber);
|
||
MemFree(*ppDest);
|
||
return status;
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeVendorInfo( PCC_VENDORINFO pVendorInfo)
|
||
{
|
||
if (pVendorInfo == NULL)
|
||
return CC_OK;
|
||
FreeOctetString(pVendorInfo->pProductNumber);
|
||
FreeOctetString(pVendorInfo->pVersionNumber);
|
||
MemFree(pVendorInfo);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
BOOL EqualConferenceIDs( PCC_CONFERENCEID pConferenceID1,
|
||
PCC_CONFERENCEID pConferenceID2)
|
||
{
|
||
ASSERT(pConferenceID1 != NULL);
|
||
ASSERT(pConferenceID2 != NULL);
|
||
|
||
if (memcmp(pConferenceID1->buffer,
|
||
pConferenceID2->buffer,
|
||
sizeof(pConferenceID1->buffer)) == 0)
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
BOOL EqualAddrs( PCC_ADDR pAddr1,
|
||
PCC_ADDR pAddr2)
|
||
{
|
||
ASSERT(pAddr1 != NULL);
|
||
ASSERT(pAddr2 != NULL);
|
||
|
||
if (pAddr1->nAddrType != pAddr2->nAddrType)
|
||
return FALSE;
|
||
|
||
if (pAddr1->bMulticast != pAddr2->bMulticast)
|
||
return FALSE;
|
||
|
||
switch (pAddr1->nAddrType) {
|
||
case CC_IP_DOMAIN_NAME:
|
||
if ((pAddr1->Addr.IP_DomainName.wPort == pAddr2->Addr.IP_DomainName.wPort) &&
|
||
(wcscmp(pAddr1->Addr.IP_DomainName.cAddr, pAddr2->Addr.IP_DomainName.cAddr) == 0))
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
case CC_IP_DOT:
|
||
if ((pAddr1->Addr.IP_Dot.wPort == pAddr2->Addr.IP_Dot.wPort) &&
|
||
(wcscmp(pAddr1->Addr.IP_Dot.cAddr, pAddr2->Addr.IP_Dot.cAddr) == 0))
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
case CC_IP_BINARY:
|
||
if ((pAddr1->Addr.IP_Binary.wPort == pAddr2->Addr.IP_Binary.wPort) &&
|
||
(pAddr1->Addr.IP_Binary.dwAddr == pAddr2->Addr.IP_Binary.dwAddr))
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
default:
|
||
ASSERT(0);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateTermCapList( PCC_TERMCAPLIST pTermCapList)
|
||
{
|
||
unsigned i, j;
|
||
|
||
if (pTermCapList == NULL)
|
||
return CC_OK;
|
||
|
||
for (i = 0; i < pTermCapList->wLength; i++)
|
||
if (pTermCapList->pTermCapArray[i] == NULL)
|
||
return CC_BAD_PARAM;
|
||
|
||
// make sure that all capability IDs are unique
|
||
for (i = 0; i < pTermCapList->wLength; i++) {
|
||
for (j = i + 1; j < pTermCapList->wLength; j++) {
|
||
if (pTermCapList->pTermCapArray[i]->CapId == pTermCapList->pTermCapArray[j]->CapId)
|
||
return CC_BAD_PARAM;
|
||
}
|
||
if ((pTermCapList->pTermCapArray[i]->CapId == H245_INVALID_CAPID) ||
|
||
(pTermCapList->pTermCapArray[i]->CapId == 0))
|
||
return CC_BAD_PARAM;
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateTermCapDescriptors( PCC_TERMCAPDESCRIPTORS pTermCapDescriptors,
|
||
PCC_TERMCAPLIST pTermCapList)
|
||
{
|
||
WORD i, j, k, l;
|
||
H245_TOTCAPDESC_T *pTermCapDescriptor;
|
||
H245_SIMCAP_T *pSimCaps;
|
||
|
||
if (pTermCapDescriptors == NULL)
|
||
return CC_OK;
|
||
|
||
for (i = 0; i < pTermCapDescriptors->wLength; i++) {
|
||
pTermCapDescriptor = pTermCapDescriptors->pTermCapDescriptorArray[i];
|
||
if ((pTermCapDescriptor->CapDescId > 255) ||
|
||
(pTermCapDescriptor->CapDesc.Length == 0) ||
|
||
(pTermCapDescriptor->CapDesc.Length > H245_MAX_SIMCAPS))
|
||
return CC_BAD_PARAM;
|
||
for (j = i + 1; j < pTermCapDescriptors->wLength; j++) {
|
||
if (pTermCapDescriptor->CapDescId ==
|
||
pTermCapDescriptors->pTermCapDescriptorArray[j]->CapDescId) {
|
||
return CC_BAD_PARAM;
|
||
}
|
||
}
|
||
for (j = 0; j < pTermCapDescriptor->CapDesc.Length; j++) {
|
||
pSimCaps = &(pTermCapDescriptor->CapDesc.SimCapArray[j]);
|
||
if ((pSimCaps->Length == 0) ||
|
||
(pSimCaps->Length > H245_MAX_ALTCAPS))
|
||
return CC_BAD_PARAM;
|
||
for (k = 0; k < pSimCaps->Length; k++) {
|
||
for (l = 0; l < pTermCapList->wLength; l++) {
|
||
if (pSimCaps->AltCaps[k] ==
|
||
pTermCapList->pTermCapArray[l]->CapId)
|
||
break;
|
||
}
|
||
if (l == pTermCapList->wLength)
|
||
// the capability descriptor contains a capability ID
|
||
// which is not present in the capability table
|
||
return CC_BAD_PARAM;
|
||
}
|
||
}
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateAddr( PCC_ADDR pAddr)
|
||
{
|
||
if (pAddr == NULL)
|
||
return CC_OK;
|
||
if ((pAddr->nAddrType != CC_IP_DOMAIN_NAME) &&
|
||
(pAddr->nAddrType != CC_IP_DOT) &&
|
||
(pAddr->nAddrType != CC_IP_BINARY))
|
||
return CC_BAD_PARAM;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyAddr( PCC_ADDR *ppDest,
|
||
PCC_ADDR pSource)
|
||
{
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
*ppDest = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
**ppDest = *pSource;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeAddr( PCC_ADDR pAddr)
|
||
{
|
||
if (pAddr == NULL)
|
||
return CC_OK;
|
||
MemFree(pAddr);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT SetQ931Port( PCC_ADDR pAddr)
|
||
{
|
||
if (pAddr == NULL)
|
||
return CC_OK;
|
||
switch (pAddr->nAddrType) {
|
||
case CC_IP_DOMAIN_NAME:
|
||
if (pAddr->Addr.IP_DomainName.wPort == 0)
|
||
pAddr->Addr.IP_DomainName.wPort = CC_H323_HOST_CALL;
|
||
return CC_OK;
|
||
case CC_IP_DOT:
|
||
if (pAddr->Addr.IP_Dot.wPort == 0)
|
||
pAddr->Addr.IP_Dot.wPort = CC_H323_HOST_CALL;
|
||
return CC_OK;
|
||
case CC_IP_BINARY:
|
||
if (pAddr->Addr.IP_Binary.wPort == 0)
|
||
pAddr->Addr.IP_Binary.wPort = CC_H323_HOST_CALL;
|
||
return CC_OK;
|
||
}
|
||
|
||
ASSERT(0);
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateDisplay( PWSTR pszDisplay)
|
||
{
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyDisplay( PWSTR *ppDest,
|
||
PWSTR pSource)
|
||
{
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
*ppDest = (WCHAR *)MemAlloc((wcslen(pSource)+1)*sizeof(WCHAR));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
wcscpy(*ppDest, pSource);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeDisplay( PWSTR pszDisplay)
|
||
{
|
||
MemFree(pszDisplay);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ValidateTerminalID( PCC_OCTETSTRING pTerminalID)
|
||
{
|
||
return ValidateOctetString(pTerminalID);
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyTerminalID( PCC_OCTETSTRING *ppDest,
|
||
PCC_OCTETSTRING pSource)
|
||
{
|
||
ASSERT(ppDest != NULL);
|
||
|
||
return CopyOctetString(ppDest, pSource);
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeTerminalID( PCC_OCTETSTRING pTerminalID)
|
||
{
|
||
return FreeOctetString(pTerminalID);
|
||
}
|
||
|
||
|
||
|
||
HRESULT SetTerminalType( TRISTATE tsMultipointController,
|
||
BYTE *pbTerminalType)
|
||
{
|
||
switch (tsMultipointController) {
|
||
case TS_TRUE:
|
||
*pbTerminalType = 240;
|
||
break;
|
||
case TS_UNKNOWN:
|
||
*pbTerminalType = 70;
|
||
break;
|
||
case TS_FALSE:
|
||
*pbTerminalType = 50;
|
||
break;
|
||
default:
|
||
ASSERT(0);
|
||
*pbTerminalType = 0;
|
||
break;
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyH245TermCapList( PCC_TERMCAPLIST *ppDest,
|
||
PCC_TERMCAPLIST pSource)
|
||
{
|
||
WORD i;
|
||
HRESULT status;
|
||
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
*ppDest = (PCC_TERMCAPLIST)MemAlloc(sizeof(CC_TERMCAPLIST));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
|
||
(*ppDest)->wLength = pSource->wLength;
|
||
(*ppDest)->pTermCapArray =
|
||
(PPCC_TERMCAP)MemAlloc(sizeof(PCC_TERMCAP) * pSource->wLength);
|
||
if ((*ppDest)->pTermCapArray == NULL) {
|
||
(*ppDest)->wLength = 0;
|
||
DestroyH245TermCapList(ppDest);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
for (i = 0; i < pSource->wLength; i++) {
|
||
status = H245CopyCap(&((*ppDest)->pTermCapArray[i]), pSource->pTermCapArray[i]);
|
||
if (status != H245_ERROR_OK) {
|
||
(*ppDest)->wLength = i;
|
||
DestroyH245TermCapList(ppDest);
|
||
return status;
|
||
}
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CopyH245TermCapDescriptors( PCC_TERMCAPDESCRIPTORS *ppDest,
|
||
PCC_TERMCAPDESCRIPTORS pSource)
|
||
{
|
||
WORD i;
|
||
HRESULT status;
|
||
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pSource == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
(*ppDest) = (PCC_TERMCAPDESCRIPTORS)MemAlloc(sizeof(CC_TERMCAPDESCRIPTORS));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
|
||
(*ppDest)->wLength = pSource->wLength;
|
||
(*ppDest)->pTermCapDescriptorArray = (H245_TOTCAPDESC_T **)MemAlloc(sizeof(H245_TOTCAPDESC_T *) *
|
||
pSource->wLength);
|
||
if ((*ppDest)->pTermCapDescriptorArray == NULL) {
|
||
(*ppDest)->wLength = 0;
|
||
DestroyH245TermCapDescriptors(ppDest);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
for (i = 0; i < pSource->wLength; i++) {
|
||
status = H245CopyCapDescriptor(&((*ppDest)->pTermCapDescriptorArray[i]),
|
||
pSource->pTermCapDescriptorArray[i]);
|
||
if (status != H245_ERROR_OK) {
|
||
(*ppDest)->wLength = i;
|
||
DestroyH245TermCapDescriptors(ppDest);
|
||
return status;
|
||
}
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CreateH245DefaultTermCapDescriptors(
|
||
PCC_TERMCAPDESCRIPTORS *ppDest,
|
||
PCC_TERMCAPLIST pTermCapList)
|
||
{
|
||
H245_TOTCAPDESC_T TermCapDescriptor;
|
||
WORD i;
|
||
HRESULT status;
|
||
|
||
ASSERT(ppDest != NULL);
|
||
|
||
if (pTermCapList == NULL) {
|
||
*ppDest = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
*ppDest = (PCC_TERMCAPDESCRIPTORS)MemAlloc(sizeof(CC_TERMCAPDESCRIPTORS));
|
||
if (*ppDest == NULL)
|
||
return CC_NO_MEMORY;
|
||
|
||
if (pTermCapList->wLength == 0) {
|
||
(*ppDest)->wLength = 0;
|
||
(*ppDest)->pTermCapDescriptorArray = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
(*ppDest)->wLength = 1;
|
||
(*ppDest)->pTermCapDescriptorArray = (H245_TOTCAPDESC_T **)MemAlloc(sizeof(H245_TOTCAPDESC_T *));
|
||
if ((*ppDest)->pTermCapDescriptorArray == NULL) {
|
||
(*ppDest)->wLength = 0;
|
||
DestroyH245TermCapDescriptors(ppDest);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
TermCapDescriptor.CapDesc.Length = pTermCapList->wLength;
|
||
TermCapDescriptor.CapDescId = 0;
|
||
|
||
for (i = 0; i < pTermCapList->wLength; i++) {
|
||
TermCapDescriptor.CapDesc.SimCapArray[i].Length = 1;
|
||
TermCapDescriptor.CapDesc.SimCapArray[i].AltCaps[0] =
|
||
pTermCapList->pTermCapArray[i]->CapId;
|
||
}
|
||
|
||
status = H245CopyCapDescriptor(&((*ppDest)->pTermCapDescriptorArray[0]),
|
||
&TermCapDescriptor);
|
||
if (status != H245_ERROR_OK) {
|
||
(*ppDest)->wLength = 0;
|
||
DestroyH245TermCapDescriptors(ppDest);
|
||
return status;
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DestroyH245TermCap( PPCC_TERMCAP ppTermCap)
|
||
{
|
||
ASSERT(ppTermCap != NULL);
|
||
|
||
if (*ppTermCap == NULL)
|
||
return CC_OK;
|
||
|
||
H245FreeCap(*ppTermCap);
|
||
*ppTermCap = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT UnregisterTermCapListFromH245(
|
||
PCONFERENCE pConference,
|
||
PCC_TERMCAPLIST pTermCapList)
|
||
{
|
||
WORD i, j;
|
||
PCALL pCall;
|
||
PCC_HCALL CallList;
|
||
WORD wNumCalls;
|
||
HRESULT status;
|
||
HRESULT SaveStatus;
|
||
|
||
ASSERT(pConference != NULL);
|
||
|
||
if (pTermCapList == NULL)
|
||
return CC_OK;
|
||
|
||
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
|
||
|
||
SaveStatus = CC_OK;
|
||
for (i = 0; i < pTermCapList->wLength; i++) {
|
||
ASSERT(pTermCapList->pTermCapArray[i] != NULL);
|
||
for (j = 0; j < wNumCalls; j++) {
|
||
if (LockCall(CallList[j], &pCall) == CC_OK) {
|
||
status = H245DelLocalCap(pCall->H245Instance,
|
||
pTermCapList->pTermCapArray[i]->CapId);
|
||
if (status != CC_OK)
|
||
SaveStatus = status;
|
||
UnlockCall(pCall);
|
||
}
|
||
}
|
||
}
|
||
if (CallList != NULL)
|
||
MemFree(CallList);
|
||
return SaveStatus;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DestroyH245TermCapList( PCC_TERMCAPLIST *ppTermCapList)
|
||
{
|
||
WORD i;
|
||
|
||
ASSERT(ppTermCapList != NULL);
|
||
|
||
if (*ppTermCapList == NULL)
|
||
return CC_OK;
|
||
|
||
for (i = 0; i < (*ppTermCapList)->wLength; i++) {
|
||
ASSERT((*ppTermCapList)->pTermCapArray[i] != NULL);
|
||
H245FreeCap((*ppTermCapList)->pTermCapArray[i]);
|
||
}
|
||
if ((*ppTermCapList)->pTermCapArray != NULL)
|
||
MemFree((*ppTermCapList)->pTermCapArray);
|
||
MemFree(*ppTermCapList);
|
||
*ppTermCapList = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT UnregisterTermCapDescriptorsFromH245(
|
||
PCONFERENCE pConference,
|
||
PCC_TERMCAPDESCRIPTORS pTermCapDescriptors)
|
||
{
|
||
WORD i, j;
|
||
PCALL pCall;
|
||
PCC_HCALL CallList;
|
||
WORD wNumCalls;
|
||
HRESULT status;
|
||
HRESULT SaveStatus;
|
||
|
||
ASSERT(pConference != NULL);
|
||
|
||
if (pTermCapDescriptors == NULL)
|
||
return CC_OK;
|
||
|
||
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
|
||
|
||
SaveStatus = CC_OK;
|
||
for (i = 0; i < pTermCapDescriptors->wLength; i++) {
|
||
ASSERT(pTermCapDescriptors->pTermCapDescriptorArray[i] != NULL);
|
||
for (j = 0; j < wNumCalls; j++) {
|
||
if (LockCall(CallList[j], &pCall) == CC_OK) {
|
||
status = H245DelCapDescriptor(pCall->H245Instance,
|
||
pTermCapDescriptors->pTermCapDescriptorArray[i]->CapDescId);
|
||
if (status != CC_OK)
|
||
SaveStatus = status;
|
||
UnlockCall(pCall);
|
||
}
|
||
}
|
||
}
|
||
if (CallList != NULL)
|
||
MemFree(CallList);
|
||
return SaveStatus;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DestroyH245TermCapDescriptors( PCC_TERMCAPDESCRIPTORS *ppTermCapDescriptors)
|
||
{
|
||
WORD i;
|
||
|
||
ASSERT(ppTermCapDescriptors != NULL);
|
||
|
||
if (*ppTermCapDescriptors == NULL)
|
||
return CC_OK;
|
||
|
||
for (i = 0; i < (*ppTermCapDescriptors)->wLength; i++) {
|
||
ASSERT((*ppTermCapDescriptors)->pTermCapDescriptorArray[i] != NULL);
|
||
H245FreeCapDescriptor((*ppTermCapDescriptors)->pTermCapDescriptorArray[i]);
|
||
}
|
||
if ((*ppTermCapDescriptors)->pTermCapDescriptorArray != NULL)
|
||
MemFree((*ppTermCapDescriptors)->pTermCapDescriptorArray);
|
||
MemFree(*ppTermCapDescriptors);
|
||
*ppTermCapDescriptors = NULL;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT HostToH245IPNetwork( BYTE *NetworkArray,
|
||
DWORD dwAddr)
|
||
{
|
||
if (NetworkArray == NULL) {
|
||
ASSERT(0);
|
||
return CC_BAD_PARAM;
|
||
}
|
||
|
||
NetworkArray[0] = HIBYTE(HIWORD(dwAddr));
|
||
NetworkArray[1] = LOBYTE(HIWORD(dwAddr));
|
||
NetworkArray[2] = HIBYTE(LOWORD(dwAddr));
|
||
NetworkArray[3] = LOBYTE(LOWORD(dwAddr));
|
||
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT H245IPNetworkToHost( DWORD *pdwAddr,
|
||
BYTE *NetworkArray)
|
||
{
|
||
if ((pdwAddr == NULL) || (NetworkArray == NULL)) {
|
||
ASSERT(0);
|
||
return CC_BAD_PARAM;
|
||
}
|
||
|
||
*pdwAddr = NetworkArray[0] * 0x01000000 +
|
||
NetworkArray[1] * 0x00010000 +
|
||
NetworkArray[2] * 0x00000100 +
|
||
NetworkArray[3] * 0x00000001;
|
||
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT ProcessRemoteHangup( CC_HCALL hCall,
|
||
HQ931CALL hQ931Initiator,
|
||
BYTE bHangupReason)
|
||
{
|
||
PCALL pCall;
|
||
CC_HCONFERENCE hConference;
|
||
PCONFERENCE pConference;
|
||
HRESULT status;
|
||
HQ931CALL hQ931Call;
|
||
H245_INST_T H245Instance;
|
||
PCHANNEL pChannel;
|
||
WORD wNumChannels;
|
||
PCC_HCHANNEL ChannelList;
|
||
WORD i;
|
||
WORD wNumCalls;
|
||
PCC_HCALL CallList;
|
||
PCALL pOldCall;
|
||
CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams;
|
||
CC_PEER_DROP_CALLBACK_PARAMS PeerDropCallbackParams;
|
||
CC_PEER_CHANGE_CAP_CALLBACK_PARAMS PeerChangeCapCallbackParams;
|
||
BOOL bConferenceTermCapsChanged;
|
||
HRESULT CallbackStatus;
|
||
|
||
if (hCall == CC_INVALID_HANDLE)
|
||
return CC_BAD_PARAM;
|
||
|
||
status = LockCallAndConference(hCall, &pCall, &pConference);
|
||
if (status != CC_OK)
|
||
return CC_BAD_PARAM;
|
||
|
||
hConference = pCall->hConference;
|
||
hQ931Call = pCall->hQ931Call;
|
||
H245Instance = pCall->H245Instance;
|
||
PeerDropCallbackParams.hCall = pCall->hCall;
|
||
if (pCall->pPeerParticipantInfo == NULL) {
|
||
PeerDropCallbackParams.TerminalLabel.bMCUNumber = 255;
|
||
PeerDropCallbackParams.TerminalLabel.bTerminalNumber = 255;
|
||
PeerDropCallbackParams.pPeerTerminalID = NULL;
|
||
} else {
|
||
PeerDropCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel;
|
||
if (pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID)
|
||
PeerDropCallbackParams.pPeerTerminalID = &pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID;
|
||
else
|
||
PeerDropCallbackParams.pPeerTerminalID = NULL;
|
||
}
|
||
|
||
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
|
||
(pConference->tsMultipointController == TS_TRUE))
|
||
CreateConferenceTermCaps(pConference, &bConferenceTermCapsChanged);
|
||
else
|
||
bConferenceTermCapsChanged = FALSE;
|
||
|
||
// Remove all TX, RX and PROXY channels associated with this call
|
||
EnumerateChannelsInConference(&wNumChannels,
|
||
&ChannelList,
|
||
pConference,
|
||
TX_CHANNEL | RX_CHANNEL | PROXY_CHANNEL);
|
||
for (i = 0; i < wNumChannels; i++) {
|
||
if (LockChannel(ChannelList[i], &pChannel) == CC_OK) {
|
||
if (pChannel->hCall == hCall)
|
||
FreeChannel(pChannel);
|
||
else
|
||
UnlockChannel(pChannel);
|
||
}
|
||
}
|
||
if (ChannelList != NULL)
|
||
MemFree(ChannelList);
|
||
|
||
switch (bHangupReason)
|
||
{
|
||
case CC_REJECT_NORMAL_CALL_CLEARING:
|
||
CallbackStatus = CC_OK;
|
||
break;
|
||
case CC_REJECT_GATEKEEPER_TERMINATED:
|
||
CallbackStatus = CC_GATEKEEPER_REFUSED;
|
||
bHangupReason = CC_REJECT_NORMAL_CALL_CLEARING;
|
||
break;
|
||
default:
|
||
CallbackStatus = CC_PEER_REJECT;
|
||
} // switch
|
||
|
||
if (pCall->CallType == THIRD_PARTY_INVITOR) {
|
||
MarkCallForDeletion(pCall);
|
||
|
||
ConnectCallbackParams.pNonStandardData = pCall->pPeerNonStandardData;
|
||
ConnectCallbackParams.pszPeerDisplay = pCall->pszPeerDisplay;
|
||
ConnectCallbackParams.bRejectReason = bHangupReason;
|
||
ConnectCallbackParams.pTermCapList = pCall->pPeerH245TermCapList;
|
||
ConnectCallbackParams.pH2250MuxCapability = pCall->pPeerH245H2250MuxCapability;
|
||
ConnectCallbackParams.pTermCapDescriptors = pCall->pPeerH245TermCapDescriptors;
|
||
ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr;
|
||
if (pCall->pQ931DestinationAddr == NULL)
|
||
ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr;
|
||
else
|
||
ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr;
|
||
ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo;
|
||
ConnectCallbackParams.bMultipointConference = TRUE;
|
||
ConnectCallbackParams.pConferenceID = &pConference->ConferenceID;
|
||
ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr;
|
||
ConnectCallbackParams.pAlternateAddress = NULL;
|
||
ConnectCallbackParams.dwUserToken = pCall->dwUserToken;
|
||
InvokeUserConferenceCallback(pConference,
|
||
CC_CONNECT_INDICATION,
|
||
CallbackStatus,
|
||
&ConnectCallbackParams);
|
||
// Need to validate the conference and call handles; the associated
|
||
// objects may have been deleted during user callback on this thread
|
||
if (ValidateConference(hConference) == CC_OK)
|
||
UnlockConference(pConference);
|
||
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
||
FreeCall(pCall);
|
||
Q931Hangup(hQ931Call, bHangupReason);
|
||
return CC_OK;
|
||
}
|
||
|
||
if (pCall->CallType == THIRD_PARTY_INTERMEDIARY) {
|
||
if ((hQ931Initiator == pCall->hQ931CallInvitor) &&
|
||
(hQ931Initiator != CC_INVALID_HANDLE)) {
|
||
pCall->hQ931CallInvitor = CC_INVALID_HANDLE;
|
||
UnlockCall(pCall);
|
||
UnlockConference(pConference);
|
||
return CC_OK;
|
||
} else {
|
||
if (pCall->CallState != CALL_COMPLETE) {
|
||
if (pCall->hQ931CallInvitor != CC_INVALID_HANDLE)
|
||
Q931Hangup(pCall->hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON);
|
||
if (ValidateCall(hCall) == CC_OK)
|
||
Q931Hangup(pCall->hQ931Call, bHangupReason);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
|
||
(pConference->tsMultipointController == TS_TRUE)) {
|
||
if (pCall->pPeerParticipantInfo != NULL) {
|
||
EnumerateCallsInConference(&wNumCalls,
|
||
&CallList,
|
||
pConference,
|
||
ESTABLISHED_CALL);
|
||
for (i = 0; i < wNumCalls; i++) {
|
||
if (CallList[i] != hCall) {
|
||
if (LockCall(CallList[i], &pOldCall) == CC_OK) {
|
||
if (pCall->pPeerParticipantInfo != NULL)
|
||
H245ConferenceIndication(
|
||
pOldCall->H245Instance,
|
||
H245_IND_TERMINAL_LEFT, // Indication Type
|
||
0, // SBE number; ignored here
|
||
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, // MCU number
|
||
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber);
|
||
if (bConferenceTermCapsChanged)
|
||
// Send new term caps
|
||
SendTermCaps(pOldCall, pConference);
|
||
UnlockCall(pOldCall);
|
||
}
|
||
}
|
||
}
|
||
if (CallList != NULL)
|
||
MemFree(CallList);
|
||
}
|
||
|
||
InvokeUserConferenceCallback(pConference,
|
||
CC_PEER_DROP_INDICATION,
|
||
CC_OK,
|
||
&PeerDropCallbackParams);
|
||
|
||
if (ValidateCall(hCall) == CC_OK)
|
||
FreeCall(pCall);
|
||
|
||
if (ValidateConference(hConference) == CC_OK) {
|
||
if (bConferenceTermCapsChanged) {
|
||
// Generate CC_PEER_CHANGE_CAP callback
|
||
PeerChangeCapCallbackParams.pTermCapList =
|
||
pConference->pConferenceTermCapList;
|
||
PeerChangeCapCallbackParams.pH2250MuxCapability =
|
||
pConference->pConferenceH245H2250MuxCapability;
|
||
PeerChangeCapCallbackParams.pTermCapDescriptors =
|
||
pConference->pConferenceTermCapDescriptors;
|
||
InvokeUserConferenceCallback(pConference,
|
||
CC_PEER_CHANGE_CAP_INDICATION,
|
||
CC_OK,
|
||
&PeerChangeCapCallbackParams);
|
||
}
|
||
}
|
||
|
||
if (ValidateConference(hConference) == CC_OK) {
|
||
if (pConference->bDeferredDelete) {
|
||
ASSERT(pConference->LocalEndpointAttached == DETACHED);
|
||
EnumerateCallsInConference(&wNumCalls, NULL, pConference, ALL_CALLS);
|
||
if (wNumCalls == 0) {
|
||
FreeConference(pConference);
|
||
return CC_OK;
|
||
}
|
||
}
|
||
UnlockConference(pConference);
|
||
}
|
||
return CC_OK;
|
||
} else {
|
||
status = EnumerateChannelsInConference(&wNumChannels,
|
||
&ChannelList,
|
||
pConference,
|
||
ALL_CHANNELS);
|
||
if (status == CC_OK) {
|
||
// free all the channels
|
||
for (i = 0; i < wNumChannels; i++) {
|
||
if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
|
||
// Notice that since we're going to hangup, we don't need to
|
||
// close any channels
|
||
FreeChannel(pChannel);
|
||
}
|
||
if (ChannelList != NULL)
|
||
MemFree(ChannelList);
|
||
}
|
||
|
||
if (H245Instance != H245_INVALID_ID)
|
||
status = H245ShutDown(H245Instance);
|
||
else
|
||
status = H245_ERROR_OK;
|
||
|
||
if (status == H245_ERROR_OK) {
|
||
status = Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
|
||
// Q931Hangup may legitimately return CS_BAD_PARAM, because the Q.931 call object
|
||
// may have been deleted at this point
|
||
if (status == CS_BAD_PARAM)
|
||
status = CC_OK;
|
||
} else
|
||
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
||
|
||
if (pConference->bDeferredDelete) {
|
||
ASSERT(pConference->LocalEndpointAttached == DETACHED);
|
||
FreeConference(pConference);
|
||
} else {
|
||
ReInitializeConference(pConference);
|
||
|
||
InvokeUserConferenceCallback(pConference,
|
||
CC_CONFERENCE_TERMINATION_INDICATION,
|
||
CallbackStatus,
|
||
NULL);
|
||
|
||
if (ValidateConference(hConference) == CC_OK)
|
||
UnlockConference(pConference);
|
||
}
|
||
return CC_OK;
|
||
}
|
||
// We should never reach this point
|
||
ASSERT(0);
|
||
}
|
||
|
||
|
||
|
||
HRESULT DefaultSessionTableConstructor(
|
||
CC_HCONFERENCE hConference,
|
||
DWORD_PTR dwConferenceToken,
|
||
BOOL bCreate,
|
||
BOOL *pbSessionTableChanged,
|
||
WORD wListCount,
|
||
PCC_TERMCAPLIST pTermCapList[],
|
||
PCC_TERMCAPDESCRIPTORS pTermCapDescriptors[],
|
||
PCC_SESSIONTABLE *ppSessionTable)
|
||
{
|
||
WORD i;
|
||
HRESULT status;
|
||
PCONFERENCE pConference;
|
||
WORD wNumChannels;
|
||
PCC_HCHANNEL ChannelList;
|
||
PCHANNEL pChannel;
|
||
WORD wNumCalls;
|
||
PCC_HCALL CallList;
|
||
PCALL pCall;
|
||
BYTE bSessionID;
|
||
WORD wPort;
|
||
DWORD dwAddr;
|
||
WCHAR szSessionDescription[100];
|
||
WCHAR ss[10];
|
||
|
||
ASSERT(hConference != CC_INVALID_HANDLE);
|
||
ASSERT(ppSessionTable != NULL);
|
||
|
||
if (*ppSessionTable != NULL) {
|
||
for (i = 0; i < (*ppSessionTable)->wLength; i++) {
|
||
if ((*ppSessionTable)->SessionInfoArray[i].pTermCap != NULL)
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
||
FreeAddr((*ppSessionTable)->SessionInfoArray[i].pRTPAddr);
|
||
FreeAddr((*ppSessionTable)->SessionInfoArray[i].pRTCPAddr);
|
||
}
|
||
if ((*ppSessionTable)->SessionInfoArray != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray);
|
||
MemFree(*ppSessionTable);
|
||
*ppSessionTable = NULL;
|
||
}
|
||
|
||
if (bCreate == FALSE)
|
||
return CC_OK;
|
||
|
||
*ppSessionTable = NULL;
|
||
if (pbSessionTableChanged != NULL)
|
||
*pbSessionTableChanged = FALSE;
|
||
|
||
status = LockConference(hConference, &pConference);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
if ((pConference->ConferenceMode == UNCONNECTED_MODE) ||
|
||
(pConference->ConferenceMode == POINT_TO_POINT_MODE)) {
|
||
UnlockConference(pConference);
|
||
return CC_BAD_PARAM;
|
||
}
|
||
|
||
// pConference->ConferenceMode == MULTIPOINT_MODE
|
||
// Create one session entry for each open channel on this conference
|
||
|
||
bSessionID = 1;
|
||
wPort = 2050;
|
||
|
||
// Set dwAddr
|
||
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
|
||
if (wNumCalls == 0) {
|
||
UnlockConference(pConference);
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
status = LockCall(CallList[0], &pCall);
|
||
if (status != CC_OK) {
|
||
MemFree(CallList);
|
||
UnlockConference(pConference);
|
||
return status;
|
||
}
|
||
|
||
if (pCall->pQ931LocalConnectAddr == NULL) {
|
||
MemFree(CallList);
|
||
UnlockCall(pCall);
|
||
UnlockConference(pConference);
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
if (pCall->pQ931LocalConnectAddr->nAddrType != CC_IP_BINARY) {
|
||
MemFree(CallList);
|
||
UnlockCall(pCall);
|
||
UnlockConference(pConference);
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
// Construct dwAddr from one of the unicast Q.931 addresses by setting the high
|
||
// nibble of the Q.931 address to 0xE
|
||
dwAddr = (pCall->pQ931LocalConnectAddr->Addr.IP_Binary.dwAddr & 0xEFFFFFFF) | 0xE0000000;
|
||
|
||
UnlockCall(pCall);
|
||
MemFree(CallList);
|
||
|
||
EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, TX_CHANNEL);
|
||
|
||
*ppSessionTable = (PCC_SESSIONTABLE)MemAlloc(sizeof(CC_SESSIONTABLE));
|
||
if (*ppSessionTable == NULL) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
(*ppSessionTable)->wLength = wNumChannels;
|
||
if (wNumChannels == 0)
|
||
(*ppSessionTable)->SessionInfoArray = NULL;
|
||
else {
|
||
(*ppSessionTable)->SessionInfoArray =
|
||
(PCC_SESSIONINFO)MemAlloc(sizeof(CC_SESSIONINFO) * wNumChannels);
|
||
if ((*ppSessionTable)->SessionInfoArray == NULL) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppSessionTable)->wLength = 0;
|
||
DefaultSessionTableConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate,
|
||
NULL, // pbSessionTableChanged,
|
||
0, // wListCount,
|
||
NULL, // pTermCapList[],
|
||
NULL, // pTermCapDescriptors[],
|
||
ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
for (i = 0; i < wNumChannels; i++) {
|
||
(*ppSessionTable)->SessionInfoArray[i].bSessionID = bSessionID++;
|
||
|
||
(*ppSessionTable)->SessionInfoArray[i].bAssociatedSessionID = 0;
|
||
|
||
wcscpy(szSessionDescription, L"Session ");
|
||
_itow((int)(*ppSessionTable)->SessionInfoArray[i].bSessionID,
|
||
ss, 10);
|
||
wcscat(szSessionDescription, ss);
|
||
|
||
(*ppSessionTable)->SessionInfoArray[i].SessionDescription.wOctetStringLength =
|
||
(WORD)((wcslen(szSessionDescription)+1)*sizeof(WCHAR));
|
||
(*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString =
|
||
(BYTE *)MemAlloc((*ppSessionTable)->SessionInfoArray[i].SessionDescription.wOctetStringLength);
|
||
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString == NULL) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppSessionTable)->wLength = i;
|
||
DefaultSessionTableConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate,
|
||
NULL, // pbSessionTableChanged,
|
||
0, // wListCount,
|
||
NULL, // pTermCapList[],
|
||
NULL, // pTermCapDescriptors[],
|
||
ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
memcpy((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString,
|
||
szSessionDescription,
|
||
(*ppSessionTable)->SessionInfoArray[i].SessionDescription.wOctetStringLength);
|
||
|
||
status = LockChannel(ChannelList[i], &pChannel);
|
||
if (status != CC_OK) {
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppSessionTable)->wLength = i;
|
||
DefaultSessionTableConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate,
|
||
NULL, // pbSessionTableChanged,
|
||
0, // wListCount,
|
||
NULL, // pTermCapList[],
|
||
NULL, // pTermCapDescriptors[],
|
||
ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
status = H245CopyCap(&(*ppSessionTable)->SessionInfoArray[i].pTermCap,
|
||
pChannel->pTxH245TermCap);
|
||
UnlockChannel(pChannel);
|
||
if (status != H245_ERROR_OK) {
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppSessionTable)->wLength = i;
|
||
DefaultSessionTableConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate,
|
||
NULL, // pbSessionTableChanged,
|
||
0, // wListCount,
|
||
NULL, // pTermCapList[],
|
||
NULL, // pTermCapDescriptors[],
|
||
ppSessionTable);
|
||
return status;
|
||
}
|
||
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr =
|
||
(PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
||
if ((*ppSessionTable)->SessionInfoArray[i].pRTPAddr == NULL) {
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppSessionTable)->wLength = i;
|
||
DefaultSessionTableConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate,
|
||
NULL, // pbSessionTableChanged,
|
||
0, // wListCount,
|
||
NULL, // pTermCapList[],
|
||
NULL, // pTermCapDescriptors[],
|
||
ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->nAddrType = CC_IP_BINARY;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->bMulticast = TRUE;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->Addr.IP_Binary.wPort = wPort++;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->Addr.IP_Binary.dwAddr = dwAddr;
|
||
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr =
|
||
(PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
||
if ((*ppSessionTable)->SessionInfoArray[i].pRTCPAddr == NULL) {
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
||
FreeAddr((*ppSessionTable)->SessionInfoArray[i].pRTPAddr);
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppSessionTable)->wLength = i;
|
||
DefaultSessionTableConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate,
|
||
NULL, // pbSessionTableChanged,
|
||
0, // wListCount,
|
||
NULL, // pTermCapList[],
|
||
NULL, // pTermCapDescriptors[],
|
||
ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->nAddrType = CC_IP_BINARY;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->bMulticast = TRUE;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->Addr.IP_Binary.wPort = wPort++;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->Addr.IP_Binary.dwAddr = dwAddr;
|
||
}
|
||
}
|
||
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
if (pbSessionTableChanged != NULL)
|
||
*pbSessionTableChanged = TRUE;
|
||
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DefaultTermCapConstructor( CC_HCONFERENCE hConference,
|
||
DWORD_PTR dwConferenceToken,
|
||
BOOL bCreate,
|
||
BOOL *pbTermCapsChanged,
|
||
WORD wListCount,
|
||
PCC_TERMCAPLIST pInTermCapList[],
|
||
PCC_TERMCAPDESCRIPTORS pInTermCapDescriptors[],
|
||
PCC_TERMCAPLIST *ppOutTermCapList,
|
||
PCC_TERMCAPDESCRIPTORS *ppOutTermCapDescriptors)
|
||
{
|
||
HRESULT status;
|
||
PCONFERENCE pConference;
|
||
WORD wNumChannels;
|
||
PCC_HCHANNEL ChannelList;
|
||
WORD i;
|
||
PCHANNEL pChannel;
|
||
|
||
ASSERT(hConference != CC_INVALID_HANDLE);
|
||
ASSERT(ppOutTermCapList != NULL);
|
||
ASSERT(ppOutTermCapDescriptors != NULL);
|
||
|
||
if (*ppOutTermCapList != NULL) {
|
||
DestroyH245TermCapList(ppOutTermCapList);
|
||
*ppOutTermCapList = NULL;
|
||
}
|
||
|
||
if (*ppOutTermCapDescriptors != NULL) {
|
||
DestroyH245TermCapDescriptors(ppOutTermCapDescriptors);
|
||
*ppOutTermCapDescriptors = NULL;
|
||
}
|
||
|
||
if (bCreate == FALSE)
|
||
return CC_OK;
|
||
|
||
*ppOutTermCapList = NULL;
|
||
*ppOutTermCapDescriptors = NULL;
|
||
if (pbTermCapsChanged != NULL)
|
||
*pbTermCapsChanged = FALSE;
|
||
|
||
status = LockConference(hConference, &pConference);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
if (pConference->LocalEndpointAttached == NEVER_ATTACHED) {
|
||
// Copy the local term caps to the conference term caps
|
||
status = CopyH245TermCapList(ppOutTermCapList, pConference->pLocalH245TermCapList);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
// Copy the local term cap descriptors to the conference term cap descriptors
|
||
status = CopyH245TermCapDescriptors(ppOutTermCapDescriptors, pConference->pLocalH245TermCapDescriptors);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
} else { // pConference->LocalEndpointAttached != NEVER_ATTACHED
|
||
// Create one term cap entry for each open channel on this conference
|
||
|
||
EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, TX_CHANNEL);
|
||
|
||
*ppOutTermCapList = (PCC_TERMCAPLIST)MemAlloc(sizeof(CC_TERMCAPLIST));
|
||
if (*ppOutTermCapList == NULL) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
(*ppOutTermCapList)->wLength = wNumChannels;
|
||
if (wNumChannels == 0)
|
||
(*ppOutTermCapList)->pTermCapArray = NULL;
|
||
else {
|
||
(*ppOutTermCapList)->pTermCapArray =
|
||
(PPCC_TERMCAP)MemAlloc(sizeof(PCC_TERMCAP) * wNumChannels);
|
||
if ((*ppOutTermCapList)->pTermCapArray == NULL) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppOutTermCapList)->wLength = 0;
|
||
DefaultTermCapConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbTermCapsChanged
|
||
0, // wListCount
|
||
NULL, // pInTermCapList[]
|
||
NULL, // pInTermCapDescriptors[]
|
||
ppOutTermCapList,
|
||
ppOutTermCapDescriptors);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
for (i = 0; i < wNumChannels; i++) {
|
||
status = LockChannel(ChannelList[i], &pChannel);
|
||
if (status != CC_OK) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppOutTermCapList)->wLength = i;
|
||
DefaultTermCapConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbTermCapsChanged
|
||
0, // wListCount
|
||
NULL, // pInTermCapList[]
|
||
NULL, // pInTermCapDescriptors[]
|
||
ppOutTermCapList,
|
||
ppOutTermCapDescriptors);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
status = H245CopyCap(&((*ppOutTermCapList)->pTermCapArray[i]),
|
||
pChannel->pTxH245TermCap);
|
||
UnlockChannel(pChannel);
|
||
if (status != H245_ERROR_OK) {
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
(*ppOutTermCapList)->wLength = i;
|
||
DefaultTermCapConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbTermCapsChanged
|
||
0, // wListCount
|
||
NULL, // pInTermCapList[]
|
||
NULL, // pInTermCapDescriptors[]
|
||
ppOutTermCapList,
|
||
ppOutTermCapDescriptors);
|
||
return status;
|
||
}
|
||
|
||
(*ppOutTermCapList)->pTermCapArray[i]->Dir = H245_CAPDIR_LCLRXTX;
|
||
(*ppOutTermCapList)->pTermCapArray[i]->CapId = (WORD)(i+1);
|
||
}
|
||
}
|
||
|
||
MemFree(ChannelList);
|
||
UnlockConference(pConference);
|
||
|
||
// create a new descriptor list
|
||
status = CreateH245DefaultTermCapDescriptors(ppOutTermCapDescriptors,
|
||
*ppOutTermCapList);
|
||
if (status != CC_OK) {
|
||
DefaultTermCapConstructor(
|
||
hConference,
|
||
dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbTermCapsChanged
|
||
0, // wListCount
|
||
NULL, // pInTermCapList[]
|
||
NULL, // pInTermCapDescriptors[]
|
||
ppOutTermCapList,
|
||
ppOutTermCapDescriptors);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
} // pConference->LocalEndpointAttached != NEVER_ATTACHED
|
||
|
||
if (pbTermCapsChanged != NULL)
|
||
*pbTermCapsChanged = TRUE;
|
||
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT AcceptCall( PCALL pCall,
|
||
PCONFERENCE pConference)
|
||
{
|
||
HRESULT status;
|
||
CC_HCALL hCall;
|
||
CC_HCONFERENCE hConference;
|
||
HQ931CALL hQ931Call;
|
||
CC_CONFERENCEID ConferenceID;
|
||
BYTE bTerminalType;
|
||
CC_ADDR H245Addr;
|
||
H245_INST_T H245Instance;
|
||
PCC_VENDORINFO pVendorInfo;
|
||
PCC_NONSTANDARDDATA pNonStandardData;
|
||
PWSTR pszDisplay;
|
||
CC_ENDPOINTTYPE DestinationEndpointType;
|
||
TRISTATE tsMultipointController;
|
||
DWORD dwLinkLayerPhysicalId;
|
||
|
||
ASSERT(pCall != NULL);
|
||
ASSERT(pConference != NULL);
|
||
|
||
hCall = pCall->hCall;
|
||
hConference = pConference->hConference;
|
||
hQ931Call = pCall->hQ931Call;
|
||
ConferenceID = pCall->ConferenceID;
|
||
pCall->hConference = pConference->hConference;
|
||
|
||
status = CopyNonStandardData(&pNonStandardData, pCall->pLocalNonStandardData);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
return status;
|
||
}
|
||
|
||
status = CopyVendorInfo(&pVendorInfo, pConference->pVendorInfo);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
FreeNonStandardData(pNonStandardData);
|
||
return status;
|
||
}
|
||
|
||
status = CopyDisplay(&pszDisplay, pCall->pszLocalDisplay);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
FreeNonStandardData(pNonStandardData);
|
||
FreeVendorInfo(pVendorInfo);
|
||
return status;
|
||
}
|
||
|
||
status = MakeH245PhysicalID(&pCall->dwH245PhysicalID);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
FreeNonStandardData(pNonStandardData);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
return status;
|
||
}
|
||
|
||
if (pCall->bCallerIsMC) {
|
||
ASSERT(pConference->tsMultipointController != TS_TRUE);
|
||
ASSERT(pConference->bMultipointCapable == TRUE);
|
||
tsMultipointController = TS_FALSE;
|
||
} else
|
||
tsMultipointController = pConference->tsMultipointController;
|
||
|
||
//MULTITHREAD
|
||
//Use a tmp ID so we don't clobber the chosen H245Id.
|
||
// H245Id=>
|
||
// <= linkLayerId
|
||
dwLinkLayerPhysicalId = INVALID_PHYS_ID;
|
||
|
||
SetTerminalType(tsMultipointController, &bTerminalType);
|
||
pCall->H245Instance = H245Init(H245_CONF_H323, // configuration
|
||
pCall->dwH245PhysicalID, // H245 physical ID
|
||
&dwLinkLayerPhysicalId, // the link layer ID is returned
|
||
hCall, // dwPreserved
|
||
(H245_CONF_IND_CALLBACK_T)H245Callback, // callback
|
||
bTerminalType);
|
||
if (pCall->H245Instance == H245_INVALID_ID) {
|
||
// H245 initialization failure
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
FreeNonStandardData(pNonStandardData);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
H245Instance = pCall->H245Instance;
|
||
|
||
// Set the H.245 TCP/IP address to the same IP address on which
|
||
// the Q.931 connection was made; this ensures that if the host
|
||
// is multi-homed, the H.245 will be made on the same IP address
|
||
// as the Q.931 connection. Set the initial H.245 port to zero,
|
||
// so that it will be dynamically determined.
|
||
ASSERT(pCall->pQ931LocalConnectAddr != NULL);
|
||
H245Addr = *pCall->pQ931LocalConnectAddr;
|
||
|
||
switch (pCall->pQ931LocalConnectAddr->nAddrType) {
|
||
case CC_IP_DOMAIN_NAME:
|
||
H245Addr.Addr.IP_DomainName.wPort = 0;
|
||
break;
|
||
case CC_IP_DOT:
|
||
H245Addr.Addr.IP_Dot.wPort = 0;
|
||
break;
|
||
case CC_IP_BINARY:
|
||
H245Addr.Addr.IP_Binary.wPort = 0;
|
||
break;
|
||
default:
|
||
ASSERT(0);
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
FreeNonStandardData(pNonStandardData);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
return CC_INTERNAL_ERROR;
|
||
}
|
||
|
||
status = linkLayerListen(&dwLinkLayerPhysicalId,
|
||
H245Instance,
|
||
&H245Addr,
|
||
NULL);
|
||
if (status != NOERROR) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
Q931RejectCall(hQ931Call, // Q931 call handle
|
||
CC_REJECT_UNDEFINED_REASON, // reject reason
|
||
&ConferenceID,
|
||
NULL, // alternate address
|
||
pNonStandardData); // non-standard data
|
||
FreeNonStandardData(pNonStandardData);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
return status;
|
||
}
|
||
|
||
UnlockConference(pConference);
|
||
UnlockCall(pCall);
|
||
|
||
DestinationEndpointType.pVendorInfo = pVendorInfo;
|
||
DestinationEndpointType.bIsTerminal = TRUE;
|
||
DestinationEndpointType.bIsGateway = FALSE;
|
||
|
||
status = Q931AcceptCall(hQ931Call,
|
||
pszDisplay,
|
||
pNonStandardData, // non-standard data
|
||
&DestinationEndpointType,
|
||
&H245Addr, // H245 address
|
||
hCall); // user token
|
||
FreeNonStandardData(pNonStandardData);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
if (status != CS_OK) {
|
||
if (LockCall(hCall, &pCall) == CC_OK)
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
return status;
|
||
}
|
||
|
||
status = LockCallAndConference(hCall, &pCall, &pConference);
|
||
if (status != CC_OK) {
|
||
if (LockCall(hCall, &pCall) == CC_OK)
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
||
return status;
|
||
}
|
||
|
||
pCall->CallState = TERMCAP;
|
||
pConference->ConferenceID = pCall->ConferenceID;
|
||
|
||
status = AddPlacedCallToConference(pCall, pConference);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
||
return status;
|
||
}
|
||
|
||
status = SendTermCaps(pCall, pConference);
|
||
if (status != CC_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
||
return status;
|
||
}
|
||
|
||
pCall->OutgoingTermCapState = AWAITING_ACK;
|
||
|
||
if (pCall->MasterSlaveState == MASTER_SLAVE_NOT_STARTED) {
|
||
status = H245InitMasterSlave(H245Instance,
|
||
H245Instance); // returned as dwTransId in the callback
|
||
if (status != H245_ERROR_OK) {
|
||
UnlockConference(pConference);
|
||
FreeCall(pCall);
|
||
H245ShutDown(H245Instance);
|
||
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
||
return status;
|
||
}
|
||
pCall->MasterSlaveState = MASTER_SLAVE_IN_PROGRESS;
|
||
}
|
||
|
||
if (pCall->bCallerIsMC) {
|
||
pConference->tsMultipointController = TS_FALSE;
|
||
pConference->ConferenceMode = MULTIPOINT_MODE;
|
||
}
|
||
|
||
UnlockConference(pConference);
|
||
UnlockCall(pCall);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT PlaceCall( PCALL pCall,
|
||
PCONFERENCE pConference)
|
||
{
|
||
CC_HCALL hCall;
|
||
HRESULT status;
|
||
WORD wGoal;
|
||
HQ931CALL hQ931Call;
|
||
PCC_ALIASNAMES pCallerAliasNames;
|
||
PCC_ALIASNAMES pCalleeAliasNames;
|
||
PCC_ALIASNAMES pCalleeExtraAliasNames;
|
||
PCC_ALIASITEM pCalleeExtension;
|
||
PCC_VENDORINFO pVendorInfo;
|
||
PWSTR pszDisplay;
|
||
PCC_NONSTANDARDDATA pNonStandardData;
|
||
WORD wNumCalls;
|
||
PCC_ADDR pConnectAddr;
|
||
PCC_ADDR pDestinationAddr;
|
||
CC_ADDR SourceAddr;
|
||
CC_ENDPOINTTYPE SourceEndpointType;
|
||
BOOL bCallerIsMC;
|
||
WORD wCallType;
|
||
|
||
ASSERT(pCall != NULL);
|
||
|
||
hCall = pCall->hCall;
|
||
|
||
if (pCall->CallState == ENQUEUED) {
|
||
// Enqueue the call on the conference object and HResultLeaveCallControl.
|
||
// There will be exactly one placed call for this conference,
|
||
// which is in the process of being placed. If this call placement
|
||
// completes successfully, all enqueued calls will then be placed.
|
||
// If this call placement fails or is terminated, one enqueued call
|
||
// will be placed
|
||
status = AddEnqueuedCallToConference(pCall, pConference);
|
||
return status;
|
||
}
|
||
|
||
// CallState == PLACED
|
||
EnumerateCallsInConference(&wNumCalls,
|
||
NULL,
|
||
pConference,
|
||
PLACED_CALL | ESTABLISHED_CALL);
|
||
if (EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID))
|
||
wGoal = CSG_CREATE;
|
||
else if ((wNumCalls == 0) && (pConference->tsMultipointController != TS_TRUE))
|
||
wGoal = CSG_JOIN;
|
||
else
|
||
wGoal = CSG_INVITE;
|
||
|
||
status = AddPlacedCallToConference(pCall, pConference);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
status = CopyAddr(&pConnectAddr, pCall->pQ931PeerConnectAddr);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
status = CopyAddr(&pDestinationAddr, pCall->pQ931DestinationAddr);
|
||
if (status != CC_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
return status;
|
||
}
|
||
|
||
status = Q931CopyAliasNames(&pCallerAliasNames, pCall->pLocalAliasNames);
|
||
if (status != CS_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
return status;
|
||
}
|
||
|
||
status = CopyVendorInfo(&pVendorInfo, pConference->pVendorInfo);
|
||
if (status != CC_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
return status;
|
||
}
|
||
|
||
status = CopyDisplay(&pszDisplay, pCall->pszLocalDisplay);
|
||
if (status != CC_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
FreeVendorInfo(pVendorInfo);
|
||
return status;
|
||
}
|
||
|
||
status = Q931CopyAliasNames(&pCalleeAliasNames, pCall->pPeerAliasNames);
|
||
if (status != CS_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
return status;
|
||
}
|
||
|
||
status = Q931CopyAliasNames(&pCalleeExtraAliasNames,
|
||
pCall->pPeerExtraAliasNames);
|
||
if (status != CS_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
Q931FreeAliasNames(pCalleeAliasNames);
|
||
return status;
|
||
}
|
||
|
||
status = Q931CopyAliasItem(&pCalleeExtension,
|
||
pCall->pPeerExtension);
|
||
if (status != CS_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
Q931FreeAliasNames(pCalleeAliasNames);
|
||
Q931FreeAliasNames(pCalleeExtraAliasNames);
|
||
return status;
|
||
}
|
||
|
||
status = CopyNonStandardData(&pNonStandardData, pCall->pLocalNonStandardData);
|
||
if (status != CC_OK) {
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
Q931FreeAliasNames(pCalleeAliasNames);
|
||
Q931FreeAliasNames(pCalleeExtraAliasNames);
|
||
Q931FreeAliasItem(pCalleeExtension);
|
||
return status;
|
||
}
|
||
|
||
bCallerIsMC = (pConference->tsMultipointController == TS_TRUE ? TRUE : FALSE);
|
||
// Note that if pConference->ConferenceMode == POINT_TO_POINT_MODE, this call attempt
|
||
// will result in a multipoint call if successful, so set the wCallType accordingly
|
||
wCallType = (WORD)((pConference->ConferenceMode == UNCONNECTED_MODE) ? CC_CALLTYPE_PT_PT : CC_CALLTYPE_N_N);
|
||
|
||
SourceEndpointType.pVendorInfo = pVendorInfo;
|
||
SourceEndpointType.bIsTerminal = TRUE;
|
||
SourceEndpointType.bIsGateway = FALSE;
|
||
|
||
// Cause our local Q.931 connect address to be placed in the
|
||
// Q.931 setup-UUIE sourceAddress field
|
||
SourceAddr.nAddrType = CC_IP_BINARY;
|
||
SourceAddr.bMulticast = FALSE;
|
||
SourceAddr.Addr.IP_Binary.dwAddr = 0;
|
||
SourceAddr.Addr.IP_Binary.wPort = 0;
|
||
|
||
status = Q931PlaceCall(&hQ931Call, // Q931 call handle
|
||
pszDisplay,
|
||
pCallerAliasNames,
|
||
pCalleeAliasNames,
|
||
pCalleeExtraAliasNames, // pCalleeExtraAliasNames
|
||
pCalleeExtension, // pCalleeExtension
|
||
pNonStandardData, // non-standard data
|
||
&SourceEndpointType,
|
||
NULL, // pszCalledPartyNumber
|
||
pConnectAddr,
|
||
pDestinationAddr,
|
||
&SourceAddr, // source address
|
||
bCallerIsMC,
|
||
&pCall->ConferenceID, // conference ID
|
||
wGoal,
|
||
wCallType,
|
||
hCall, // user token
|
||
(Q931_CALLBACK)Q931Callback, // callback
|
||
#ifdef GATEKEEPER
|
||
pCall->GkiCall.usCRV, // CRV
|
||
&pCall->CallIdentifier); // H.225 CallIdentifier
|
||
#else
|
||
0, // CRV
|
||
&pCall->CallIdentifier); // H.225 CallIdentifier
|
||
|
||
#endif GATEKEEPER
|
||
FreeAddr(pConnectAddr);
|
||
FreeAddr(pDestinationAddr);
|
||
Q931FreeAliasNames(pCallerAliasNames);
|
||
FreeVendorInfo(pVendorInfo);
|
||
FreeDisplay(pszDisplay);
|
||
Q931FreeAliasNames(pCalleeAliasNames);
|
||
Q931FreeAliasNames(pCalleeExtraAliasNames);
|
||
Q931FreeAliasItem(pCalleeExtension);
|
||
FreeNonStandardData(pNonStandardData);
|
||
if (status != CS_OK)
|
||
return status;
|
||
|
||
pCall->hQ931Call = hQ931Call;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT SendTermCaps( PCALL pCall,
|
||
PCONFERENCE pConference)
|
||
{
|
||
HRESULT status;
|
||
WORD i;
|
||
H245_TOTCAPDESC_T *pTermCapDescriptor;
|
||
PCC_TERMCAP pH2250MuxCapability;
|
||
PCC_TERMCAPLIST pTermCapList;
|
||
PCC_TERMCAPDESCRIPTORS pTermCapDescriptors;
|
||
|
||
ASSERT(pCall != NULL);
|
||
ASSERT(pConference != NULL);
|
||
|
||
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
|
||
(pConference->tsMultipointController == TS_TRUE)) {
|
||
pH2250MuxCapability = pConference->pConferenceH245H2250MuxCapability;
|
||
pTermCapList = pConference->pConferenceTermCapList;
|
||
pTermCapDescriptors = pConference->pConferenceTermCapDescriptors;
|
||
} else {
|
||
pH2250MuxCapability = pConference->pLocalH245H2250MuxCapability;
|
||
pTermCapList = pConference->pLocalH245TermCapList;
|
||
pTermCapDescriptors = pConference->pLocalH245TermCapDescriptors;
|
||
}
|
||
|
||
ASSERT(pH2250MuxCapability != NULL);
|
||
ASSERT(pTermCapList != NULL);
|
||
ASSERT(pTermCapDescriptors != NULL);
|
||
|
||
// First send out the H.225.0 capability
|
||
status = H245SetLocalCap(pCall->H245Instance,
|
||
pH2250MuxCapability,
|
||
&pH2250MuxCapability->CapId);
|
||
ASSERT(pH2250MuxCapability->CapId == 0);
|
||
if (status != H245_ERROR_OK)
|
||
return status;
|
||
|
||
// Now send out the terminal capabilities
|
||
for (i = 0; i < pTermCapList->wLength; i++) {
|
||
status = H245SetLocalCap(pCall->H245Instance,
|
||
pTermCapList->pTermCapArray[i],
|
||
&pTermCapList->pTermCapArray[i]->CapId);
|
||
if (status != H245_ERROR_OK)
|
||
return status;
|
||
}
|
||
|
||
// Finally send out the capability descriptors
|
||
for (i = 0; i < pTermCapDescriptors->wLength; i++) {
|
||
pTermCapDescriptor = pTermCapDescriptors->pTermCapDescriptorArray[i];
|
||
status = H245SetCapDescriptor(pCall->H245Instance,
|
||
&pTermCapDescriptor->CapDesc,
|
||
&pTermCapDescriptor->CapDescId);
|
||
if (status != H245_ERROR_OK)
|
||
return status;
|
||
}
|
||
|
||
status = H245SendTermCaps(pCall->H245Instance,
|
||
pCall->H245Instance); // returned as dwTransId in the callback
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT SessionTableToH245CommunicationTable(
|
||
PCC_SESSIONTABLE pSessionTable,
|
||
H245_COMM_MODE_ENTRY_T *pH245CommunicationTable[],
|
||
BYTE *pbCommunicationTableCount)
|
||
{
|
||
WORD i, j;
|
||
WORD wStringLength;
|
||
|
||
ASSERT(pH245CommunicationTable != NULL);
|
||
ASSERT(pbCommunicationTableCount != NULL);
|
||
|
||
if ((pSessionTable == NULL) || (pSessionTable->wLength == 0)) {
|
||
*pH245CommunicationTable = NULL;
|
||
*pbCommunicationTableCount = 0;
|
||
return CC_OK;
|
||
}
|
||
|
||
if (pSessionTable->SessionInfoArray == NULL) {
|
||
*pH245CommunicationTable = NULL;
|
||
*pbCommunicationTableCount = 0;
|
||
return CC_BAD_PARAM;
|
||
}
|
||
|
||
*pH245CommunicationTable = (H245_COMM_MODE_ENTRY_T *)MemAlloc(sizeof(H245_COMM_MODE_ENTRY_T) * pSessionTable->wLength);
|
||
if (*pH245CommunicationTable == NULL) {
|
||
*pbCommunicationTableCount = 0;
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
*pbCommunicationTableCount = (BYTE)pSessionTable->wLength;
|
||
|
||
for (i = 0; i < pSessionTable->wLength; i++) {
|
||
(*pH245CommunicationTable)[i].pNonStandard = NULL;
|
||
(*pH245CommunicationTable)[i].sessionID = pSessionTable->SessionInfoArray[i].bSessionID;
|
||
if (pSessionTable->SessionInfoArray[i].bAssociatedSessionID == 0)
|
||
(*pH245CommunicationTable)[i].associatedSessionIDPresent = FALSE;
|
||
else {
|
||
(*pH245CommunicationTable)[i].associatedSessionIDPresent = TRUE;
|
||
(*pH245CommunicationTable)[i].associatedSessionID = pSessionTable->SessionInfoArray[i].bAssociatedSessionID;
|
||
}
|
||
(*pH245CommunicationTable)[i].terminalLabelPresent = FALSE;
|
||
wStringLength = pSessionTable->SessionInfoArray[i].SessionDescription.wOctetStringLength;
|
||
if (wStringLength > 0) {
|
||
(*pH245CommunicationTable)[i].pSessionDescription = (unsigned short *)MemAlloc(sizeof(unsigned short) * wStringLength);
|
||
if ((*pH245CommunicationTable)[i].pSessionDescription == NULL) {
|
||
for (j = 0; j < i; j++)
|
||
MemFree((*pH245CommunicationTable)[j].pSessionDescription);
|
||
MemFree(*pH245CommunicationTable);
|
||
*pbCommunicationTableCount = 0;
|
||
return CC_NO_MEMORY;
|
||
}
|
||
memcpy((*pH245CommunicationTable)[i].pSessionDescription,
|
||
pSessionTable->SessionInfoArray[i].SessionDescription.pOctetString,
|
||
wStringLength);
|
||
} else
|
||
(*pH245CommunicationTable)[i].pSessionDescription = NULL;
|
||
(*pH245CommunicationTable)[i].wSessionDescriptionLength = wStringLength;
|
||
(*pH245CommunicationTable)[i].dataType = *pSessionTable->SessionInfoArray[i].pTermCap;
|
||
if (pSessionTable->SessionInfoArray[i].pRTPAddr == NULL)
|
||
(*pH245CommunicationTable)[i].mediaChannelPresent = FALSE;
|
||
else {
|
||
if (pSessionTable->SessionInfoArray[i].pRTPAddr->nAddrType != CC_IP_BINARY) {
|
||
for (j = 0; j <= i; j++)
|
||
if ((*pH245CommunicationTable)[j].pSessionDescription != NULL)
|
||
MemFree((*pH245CommunicationTable)[j].pSessionDescription);
|
||
MemFree(*pH245CommunicationTable);
|
||
*pbCommunicationTableCount = 0;
|
||
return CC_BAD_PARAM;
|
||
}
|
||
if (pSessionTable->SessionInfoArray[i].pRTPAddr->bMulticast)
|
||
(*pH245CommunicationTable)[i].mediaChannel.type = H245_IP_MULTICAST;
|
||
else
|
||
(*pH245CommunicationTable)[i].mediaChannel.type = H245_IP_UNICAST;
|
||
(*pH245CommunicationTable)[i].mediaChannel.u.ip.tsapIdentifier =
|
||
pSessionTable->SessionInfoArray[i].pRTPAddr->Addr.IP_Binary.wPort;
|
||
HostToH245IPNetwork((*pH245CommunicationTable)[i].mediaChannel.u.ip.network,
|
||
pSessionTable->SessionInfoArray[i].pRTPAddr->Addr.IP_Binary.dwAddr);
|
||
(*pH245CommunicationTable)[i].mediaChannelPresent = TRUE;
|
||
}
|
||
if (pSessionTable->SessionInfoArray[i].pRTCPAddr == NULL)
|
||
(*pH245CommunicationTable)[i].mediaControlChannelPresent = FALSE;
|
||
else {
|
||
if (pSessionTable->SessionInfoArray[i].pRTCPAddr->nAddrType != CC_IP_BINARY) {
|
||
for (j = 0; j <= i; j++)
|
||
if ((*pH245CommunicationTable)[j].pSessionDescription != NULL)
|
||
MemFree((*pH245CommunicationTable)[j].pSessionDescription);
|
||
MemFree(*pH245CommunicationTable);
|
||
*pbCommunicationTableCount = 0;
|
||
return CC_BAD_PARAM;
|
||
}
|
||
if (pSessionTable->SessionInfoArray[i].pRTCPAddr->bMulticast)
|
||
(*pH245CommunicationTable)[i].mediaControlChannel.type = H245_IP_MULTICAST;
|
||
else
|
||
(*pH245CommunicationTable)[i].mediaControlChannel.type = H245_IP_UNICAST;
|
||
(*pH245CommunicationTable)[i].mediaControlChannel.u.ip.tsapIdentifier =
|
||
pSessionTable->SessionInfoArray[i].pRTCPAddr->Addr.IP_Binary.wPort;
|
||
HostToH245IPNetwork((*pH245CommunicationTable)[i].mediaControlChannel.u.ip.network,
|
||
pSessionTable->SessionInfoArray[i].pRTCPAddr->Addr.IP_Binary.dwAddr);
|
||
(*pH245CommunicationTable)[i].mediaControlChannelPresent = TRUE;
|
||
}
|
||
(*pH245CommunicationTable)[i].mediaGuaranteed = FALSE;
|
||
(*pH245CommunicationTable)[i].mediaGuaranteedPresent = TRUE;
|
||
(*pH245CommunicationTable)[i].mediaControlGuaranteed = FALSE;
|
||
(*pH245CommunicationTable)[i].mediaControlGuaranteedPresent = TRUE;
|
||
}
|
||
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT H245CommunicationTableToSessionTable(
|
||
H245_COMM_MODE_ENTRY_T H245CommunicationTable[],
|
||
BYTE bCommunicationTableCount,
|
||
PCC_SESSIONTABLE *ppSessionTable)
|
||
{
|
||
WORD i, j;
|
||
HRESULT status;
|
||
|
||
ASSERT(ppSessionTable != NULL);
|
||
|
||
if (H245CommunicationTable == NULL)
|
||
if (bCommunicationTableCount == 0) {
|
||
*ppSessionTable = NULL;
|
||
return CC_OK;
|
||
} else
|
||
return CC_BAD_PARAM;
|
||
else
|
||
if (bCommunicationTableCount == 0)
|
||
return CC_BAD_PARAM;
|
||
|
||
*ppSessionTable = (PCC_SESSIONTABLE)MemAlloc(sizeof(CC_SESSIONTABLE));
|
||
if (*ppSessionTable == NULL)
|
||
return CC_NO_MEMORY;
|
||
|
||
(*ppSessionTable)->wLength = bCommunicationTableCount;
|
||
|
||
(*ppSessionTable)->SessionInfoArray = (PCC_SESSIONINFO)MemAlloc(sizeof(CC_SESSIONINFO) * bCommunicationTableCount);
|
||
if ((*ppSessionTable)->SessionInfoArray == NULL) {
|
||
MemFree(*ppSessionTable);
|
||
*ppSessionTable = NULL;
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
for (i = 0; i < bCommunicationTableCount; i++) {
|
||
(*ppSessionTable)->SessionInfoArray[i].bSessionID = H245CommunicationTable[i].sessionID;
|
||
if (H245CommunicationTable[i].associatedSessionIDPresent)
|
||
(*ppSessionTable)->SessionInfoArray[i].bAssociatedSessionID =
|
||
H245CommunicationTable[i].associatedSessionID;
|
||
else
|
||
(*ppSessionTable)->SessionInfoArray[i].bAssociatedSessionID = 0;
|
||
(*ppSessionTable)->SessionInfoArray[i].SessionDescription.wOctetStringLength =
|
||
H245CommunicationTable[i].wSessionDescriptionLength;
|
||
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.wOctetStringLength == 0)
|
||
(*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString = NULL;
|
||
else {
|
||
(*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString =
|
||
(BYTE *)MemAlloc(H245CommunicationTable[i].wSessionDescriptionLength);
|
||
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString == NULL) {
|
||
for (j = 0; j < i; j++) {
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[j].pTermCap);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
||
}
|
||
MemFree((*ppSessionTable)->SessionInfoArray);
|
||
MemFree(*ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
memcpy((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString,
|
||
H245CommunicationTable[i].pSessionDescription,
|
||
H245CommunicationTable[i].wSessionDescriptionLength);
|
||
}
|
||
status = H245CopyCap(&(*ppSessionTable)->SessionInfoArray[i].pTermCap,
|
||
&H245CommunicationTable[i].dataType);
|
||
if (status != H245_ERROR_OK) {
|
||
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
for (j = 0; j < i; j++) {
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[j].pTermCap);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
||
}
|
||
MemFree((*ppSessionTable)->SessionInfoArray);
|
||
MemFree(*ppSessionTable);
|
||
return status;
|
||
}
|
||
if ((H245CommunicationTable[i].mediaChannelPresent) &&
|
||
((H245CommunicationTable[i].mediaChannel.type == H245_IP_MULTICAST) ||
|
||
(H245CommunicationTable[i].mediaChannel.type == H245_IP_UNICAST))) {
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
||
if ((*ppSessionTable)->SessionInfoArray[i].pRTPAddr == NULL) {
|
||
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
||
for (j = 0; j < i; j++) {
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[j].pTermCap);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
||
}
|
||
MemFree((*ppSessionTable)->SessionInfoArray);
|
||
MemFree(*ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->nAddrType = CC_IP_BINARY;
|
||
if (H245CommunicationTable[i].mediaChannel.type == H245_IP_MULTICAST)
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->bMulticast = TRUE;
|
||
else
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->bMulticast = FALSE;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->Addr.IP_Binary.wPort =
|
||
H245CommunicationTable[i].mediaChannel.u.ip.tsapIdentifier;
|
||
H245IPNetworkToHost(&(*ppSessionTable)->SessionInfoArray[i].pRTPAddr->Addr.IP_Binary.dwAddr,
|
||
H245CommunicationTable[i].mediaChannel.u.ip.network);
|
||
} else
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTPAddr = NULL;
|
||
if ((H245CommunicationTable[i].mediaControlChannelPresent) &&
|
||
((H245CommunicationTable[i].mediaControlChannel.type == H245_IP_MULTICAST) ||
|
||
(H245CommunicationTable[i].mediaControlChannel.type == H245_IP_UNICAST))) {
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
||
if ((*ppSessionTable)->SessionInfoArray[i].pRTCPAddr == NULL) {
|
||
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
||
if ((*ppSessionTable)->SessionInfoArray[i].pRTPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[i].pRTPAddr);
|
||
for (j = 0; j < i; j++) {
|
||
H245FreeCap((*ppSessionTable)->SessionInfoArray[j].pTermCap);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
||
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
||
MemFree((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
||
}
|
||
MemFree((*ppSessionTable)->SessionInfoArray);
|
||
MemFree(*ppSessionTable);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->nAddrType = CC_IP_BINARY;
|
||
if (H245CommunicationTable[i].mediaChannel.type == H245_IP_MULTICAST)
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->bMulticast = TRUE;
|
||
else
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->bMulticast = FALSE;
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->Addr.IP_Binary.wPort =
|
||
H245CommunicationTable[i].mediaControlChannel.u.ip.tsapIdentifier;
|
||
H245IPNetworkToHost(&(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr->Addr.IP_Binary.dwAddr,
|
||
H245CommunicationTable[i].mediaControlChannel.u.ip.network);
|
||
} else
|
||
(*ppSessionTable)->SessionInfoArray[i].pRTCPAddr = NULL;
|
||
}
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeH245CommunicationTable( H245_COMM_MODE_ENTRY_T H245CommunicationTable[],
|
||
BYTE bCommunicationTableCount)
|
||
{
|
||
WORD i;
|
||
|
||
if (H245CommunicationTable == NULL)
|
||
if (bCommunicationTableCount == 0)
|
||
return CC_OK;
|
||
else
|
||
return CC_BAD_PARAM;
|
||
else
|
||
if (bCommunicationTableCount == 0)
|
||
return CC_BAD_PARAM;
|
||
|
||
for (i = 0; i < bCommunicationTableCount; i++)
|
||
if (H245CommunicationTable[i].pSessionDescription != NULL)
|
||
MemFree(H245CommunicationTable[i].pSessionDescription);
|
||
MemFree(H245CommunicationTable);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT _PrepareTermCapLists( PCONFERENCE pConference,
|
||
WORD *pwListCount,
|
||
PCC_TERMCAPLIST **ppTermCapList,
|
||
PCC_TERMCAPDESCRIPTORS **ppTermCapDescriptorList,
|
||
PCALL *pCallList[])
|
||
{
|
||
WORD i;
|
||
WORD wNumCalls;
|
||
WORD wOffset;
|
||
PCC_HCALL CallList;
|
||
PCALL pCall;
|
||
|
||
ASSERT(pConference != NULL);
|
||
ASSERT(pwListCount != NULL);
|
||
ASSERT(ppTermCapList != NULL);
|
||
ASSERT(ppTermCapDescriptorList != NULL);
|
||
ASSERT(pCallList != NULL);
|
||
|
||
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
|
||
|
||
if ((pConference->LocalEndpointAttached == DETACHED) && (wNumCalls > 0))
|
||
wOffset = 0;
|
||
else
|
||
// LocalEndpointAttached is either UNATTACHED or ATTACHED, or there are no calls
|
||
// in the conference; in the latter case, we need to have some term caps in
|
||
// order to form the conference term cap set (which cannot be empty)
|
||
wOffset = 1;
|
||
|
||
*pwListCount = (WORD)(wNumCalls + wOffset);
|
||
|
||
*ppTermCapList = (PCC_TERMCAPLIST *)MemAlloc(sizeof(PCC_TERMCAPLIST) * (*pwListCount));
|
||
if (*ppTermCapList == NULL) {
|
||
MemFree(CallList);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
*ppTermCapDescriptorList = (PCC_TERMCAPDESCRIPTORS *)MemAlloc(sizeof(PCC_TERMCAPDESCRIPTORS) * (*pwListCount));
|
||
if (*ppTermCapDescriptorList == NULL) {
|
||
MemFree(CallList);
|
||
MemFree(*ppTermCapList);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
*pCallList = (PCALL *)MemAlloc(sizeof(PCALL) * (*pwListCount));
|
||
if (*pCallList == NULL) {
|
||
MemFree(CallList);
|
||
MemFree(*ppTermCapList);
|
||
MemFree(*ppTermCapDescriptorList);
|
||
return CC_NO_MEMORY;
|
||
}
|
||
|
||
// Fill in pTermCapList and pTermCapDescriptorList
|
||
if (wOffset == 1) {
|
||
// The local endpoint is attached to the conference, so fill in the first
|
||
// slot in both lists with the local term cap and descriptor lists
|
||
(*ppTermCapList)[0] = pConference->pLocalH245TermCapList;
|
||
(*ppTermCapDescriptorList)[0] = pConference->pLocalH245TermCapDescriptors;
|
||
}
|
||
for (i = 0; i < wNumCalls; i++) {
|
||
if (LockCall(CallList[i], &pCall) == CC_OK) {
|
||
(*ppTermCapList)[i+wOffset] = pCall->pPeerH245TermCapList;
|
||
(*ppTermCapDescriptorList)[i+wOffset] = pCall->pPeerH245TermCapDescriptors;
|
||
(*pCallList)[i] = pCall;
|
||
} else {
|
||
(*ppTermCapList)[i+wOffset] = NULL;
|
||
(*ppTermCapDescriptorList)[i+wOffset] = NULL;
|
||
(*pCallList)[i] = NULL;
|
||
}
|
||
}
|
||
for (i = 0; i < wOffset; i++)
|
||
(*pCallList)[wNumCalls+i] = NULL;
|
||
MemFree(CallList);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT _FreeTermCapLists( WORD wListCount,
|
||
PCC_TERMCAPLIST *pTermCapList,
|
||
PCC_TERMCAPDESCRIPTORS *pTermCapDescriptorList,
|
||
PCALL pCallList[])
|
||
{
|
||
WORD i;
|
||
|
||
for (i = 0; i < wListCount; i++)
|
||
if (pCallList[i] != NULL)
|
||
UnlockCall(pCallList[i]);
|
||
if (pTermCapList != NULL)
|
||
MemFree(pTermCapList);
|
||
if (pTermCapDescriptorList != NULL)
|
||
MemFree(pTermCapDescriptorList);
|
||
MemFree(pCallList);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CreateConferenceSessionTable(
|
||
PCONFERENCE pConference,
|
||
BOOL *pbSessionTableChanged)
|
||
{
|
||
HRESULT status;
|
||
PCALL *pCallList;
|
||
PCC_TERMCAPLIST *pTermCapList;
|
||
PCC_TERMCAPDESCRIPTORS *pTermCapDescriptorList;
|
||
WORD wListCount;
|
||
|
||
ASSERT(pConference != NULL);
|
||
|
||
if (pConference->bSessionTableInternallyConstructed == TRUE) {
|
||
status = FreeConferenceSessionTable(pConference);
|
||
if (status != CC_OK)
|
||
return status;
|
||
pConference->bSessionTableInternallyConstructed = FALSE;
|
||
}
|
||
|
||
status = _PrepareTermCapLists(pConference,
|
||
&wListCount,
|
||
&pTermCapList,
|
||
&pTermCapDescriptorList,
|
||
&pCallList);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
status = pConference->SessionTableConstructor(
|
||
pConference->hConference,
|
||
pConference->dwConferenceToken,
|
||
TRUE, // bCreate
|
||
pbSessionTableChanged,
|
||
wListCount,
|
||
pTermCapList,
|
||
pTermCapDescriptorList,
|
||
&pConference->pSessionTable);
|
||
|
||
_FreeTermCapLists(wListCount,
|
||
pTermCapList,
|
||
pTermCapDescriptorList,
|
||
pCallList);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeConferenceSessionTable( PCONFERENCE pConference)
|
||
{
|
||
HRESULT status;
|
||
|
||
ASSERT(pConference != NULL);
|
||
|
||
if (pConference->bSessionTableInternallyConstructed)
|
||
status = DefaultSessionTableConstructor(
|
||
pConference->hConference,
|
||
pConference->dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbSessionTableChanged
|
||
0, // wListCount
|
||
NULL, // pTermCapList[]
|
||
NULL, // pTermCapDescriptors[]
|
||
&pConference->pSessionTable);
|
||
else
|
||
status = pConference->SessionTableConstructor(
|
||
pConference->hConference,
|
||
pConference->dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbSessionTableChanged
|
||
0, // wListCount
|
||
NULL, // pTermCapList[]
|
||
NULL, // pTermCapDescriptors[]
|
||
&pConference->pSessionTable);
|
||
pConference->pSessionTable = NULL;
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT CreateConferenceTermCaps( PCONFERENCE pConference,
|
||
BOOL *pbTermCapsChanged)
|
||
{
|
||
HRESULT status;
|
||
WORD wListCount;
|
||
PCALL *pCallList;
|
||
PCC_TERMCAPLIST *pInTermCapList;
|
||
PCC_TERMCAPDESCRIPTORS *pInTermCapDescriptors;
|
||
|
||
ASSERT(pConference != NULL);
|
||
|
||
if (pConference->pConferenceH245H2250MuxCapability != NULL)
|
||
H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
|
||
|
||
ASSERT(pConference->pLocalH245H2250MuxCapability != NULL);
|
||
status = H245CopyCap(&pConference->pConferenceH245H2250MuxCapability,
|
||
pConference->pLocalH245H2250MuxCapability);
|
||
if (status != H245_ERROR_OK)
|
||
return status;
|
||
|
||
status = _PrepareTermCapLists(pConference,
|
||
&wListCount,
|
||
&pInTermCapList,
|
||
&pInTermCapDescriptors,
|
||
&pCallList);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
status = UnregisterTermCapListFromH245(pConference,
|
||
pConference->pConferenceTermCapList);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
status = UnregisterTermCapDescriptorsFromH245(pConference,
|
||
pConference->pConferenceTermCapDescriptors);
|
||
if (status != CC_OK)
|
||
return status;
|
||
|
||
status = pConference->TermCapConstructor(
|
||
pConference->hConference,
|
||
pConference->dwConferenceToken,
|
||
TRUE, // bCreate
|
||
pbTermCapsChanged,
|
||
wListCount,
|
||
pInTermCapList,
|
||
pInTermCapDescriptors,
|
||
&pConference->pConferenceTermCapList,
|
||
&pConference->pConferenceTermCapDescriptors);
|
||
|
||
_FreeTermCapLists(wListCount,
|
||
pInTermCapList,
|
||
pInTermCapDescriptors,
|
||
pCallList);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FreeConferenceTermCaps( PCONFERENCE pConference)
|
||
{
|
||
HRESULT status;
|
||
|
||
ASSERT(pConference != NULL);
|
||
|
||
status = pConference->TermCapConstructor(
|
||
pConference->hConference,
|
||
pConference->dwConferenceToken,
|
||
FALSE, // bCreate
|
||
NULL, // pbTermCapsChanged
|
||
0, // wListCount
|
||
NULL, // pInTermCapList[]
|
||
NULL, // pInTermCapDescriptors[]
|
||
&pConference->pConferenceTermCapList,
|
||
&pConference->pConferenceTermCapDescriptors);
|
||
pConference->pConferenceTermCapList = NULL;
|
||
pConference->pConferenceTermCapDescriptors = NULL;
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
HRESULT FindEnqueuedRequest( PCALL_QUEUE pQueueHead,
|
||
CC_HCALL hEnqueuedCall)
|
||
{
|
||
PCALL_QUEUE pQueueItem;
|
||
|
||
ASSERT(hEnqueuedCall != CC_INVALID_HANDLE);
|
||
|
||
pQueueItem = pQueueHead;
|
||
|
||
while (pQueueItem != NULL) {
|
||
if (pQueueItem->hCall == hEnqueuedCall)
|
||
break;
|
||
pQueueItem = pQueueItem->pNext;
|
||
}
|
||
if (pQueueItem == NULL)
|
||
return CC_BAD_PARAM;
|
||
else
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT EnqueueRequest( PCALL_QUEUE *ppQueueHead,
|
||
CC_HCALL hEnqueuedCall)
|
||
{
|
||
PCALL_QUEUE pQueueItem;
|
||
|
||
ASSERT(ppQueueHead != NULL);
|
||
ASSERT(hEnqueuedCall != CC_INVALID_HANDLE);
|
||
|
||
// Make sure we're not enqueuing a duplicate request
|
||
pQueueItem = *ppQueueHead;
|
||
while (pQueueItem != NULL) {
|
||
if (pQueueItem->hCall == hEnqueuedCall)
|
||
return CC_OK;
|
||
pQueueItem = pQueueItem->pNext;
|
||
}
|
||
|
||
pQueueItem = (PCALL_QUEUE)MemAlloc(sizeof(CALL_QUEUE));
|
||
if (pQueueItem == NULL)
|
||
return CC_NO_MEMORY;
|
||
pQueueItem->hCall = hEnqueuedCall;
|
||
pQueueItem->pPrev = NULL;
|
||
pQueueItem->pNext = *ppQueueHead;
|
||
if (*ppQueueHead != NULL)
|
||
(*ppQueueHead)->pPrev = pQueueItem;
|
||
*ppQueueHead = pQueueItem;
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DequeueRequest( PCALL_QUEUE *ppQueueHead,
|
||
PCC_HCALL phEnqueuedCall)
|
||
|
||
{
|
||
PCALL_QUEUE pQueueItem;
|
||
|
||
ASSERT(ppQueueHead != NULL);
|
||
|
||
if (phEnqueuedCall != NULL)
|
||
*phEnqueuedCall = CC_INVALID_HANDLE;
|
||
|
||
if (*ppQueueHead == NULL)
|
||
return CC_BAD_PARAM;
|
||
|
||
pQueueItem = *ppQueueHead;
|
||
*ppQueueHead = (*ppQueueHead)->pNext;
|
||
if (*ppQueueHead != NULL)
|
||
(*ppQueueHead)->pPrev = NULL;
|
||
|
||
if (phEnqueuedCall != NULL)
|
||
*phEnqueuedCall = pQueueItem->hCall;
|
||
MemFree(pQueueItem);
|
||
return CC_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT DequeueSpecificRequest( PCALL_QUEUE *ppQueueHead,
|
||
CC_HCALL hEnqueuedCall)
|
||
{
|
||
PCALL_QUEUE pQueueItem;
|
||
|
||
ASSERT(ppQueueHead != NULL);
|
||
ASSERT(hEnqueuedCall != CC_INVALID_HANDLE);
|
||
|
||
pQueueItem = *ppQueueHead;
|
||
while (pQueueItem != NULL)
|
||
if (pQueueItem->hCall == hEnqueuedCall)
|
||
break;
|
||
else
|
||
pQueueItem = pQueueItem->pNext;
|
||
|
||
if (pQueueItem == NULL)
|
||
return CC_BAD_PARAM;
|
||
|
||
if (pQueueItem->pNext != NULL)
|
||
pQueueItem->pNext->pPrev = pQueueItem->pPrev;
|
||
if (pQueueItem->pPrev == NULL)
|
||
*ppQueueHead = pQueueItem->pNext;
|
||
else
|
||
pQueueItem->pPrev->pNext = pQueueItem->pNext;
|
||
|
||
MemFree(pQueueItem);
|
||
return CC_OK;
|
||
}
|
||
|