2825 lines
79 KiB
C
2825 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.1.0 $
|
|
* $Date: 20 Jun 1997 14:19:02 $
|
|
* $Author: MANDREWS $
|
|
*
|
|
* Deliverable:
|
|
*
|
|
* Abstract:
|
|
*
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
#pragma warning ( disable : 4057 4100 4115 4201 4214 4244)
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winreg.h>
|
|
#pragma warning ( default : 4115 4201 4214 )
|
|
#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"
|
|
#include "provider.h"
|
|
|
|
extern CC_CONFERENCEID InvalidConferenceID;
|
|
|
|
|
|
|
|
// The following two procedures are currently obsolete. They're kept
|
|
// around in case we need them in the future
|
|
#if 0
|
|
void * MallocDbg( DWORD dwSize,
|
|
PSTR pszFile,
|
|
int nLine)
|
|
{
|
|
void *pMem;
|
|
|
|
ASSERT(dwSize != 0);
|
|
|
|
pMem = GlobalAlloc(GMEM_FIXED, dwSize);
|
|
|
|
#ifdef MEM_TRACE
|
|
printf("MALLOC %s %d %lu %08x\n",
|
|
pszFile, nLine, dwSize, pMem);
|
|
#endif // MEM_TRACE
|
|
|
|
return pMem;
|
|
}
|
|
|
|
|
|
|
|
void FreeDbg( void * pMem,
|
|
PSTR pszFile,
|
|
int nLine)
|
|
{
|
|
ASSERT(pMem != NULL);
|
|
|
|
GlobalFree(pMem);
|
|
|
|
#ifdef MEM_TRACE
|
|
printf("FREE %s %d %08x\n",
|
|
pszFile, nLine, pMem);
|
|
#endif // MEM_TRACE
|
|
}
|
|
#endif // 0
|
|
|
|
|
|
|
|
HRESULT InitializeLock( PLOCK pLock)
|
|
{
|
|
ASSERT(pLock != NULL);
|
|
|
|
#ifdef DBG
|
|
|
|
__try {
|
|
|
|
// initialize lock (and allocate event immediately)
|
|
InitializeCriticalSectionAndSpinCount(&pLock->LockInfoLock,H323_SPIN_COUNT);
|
|
|
|
} __except ((GetExceptionCode() == STATUS_NO_MEMORY)
|
|
? EXCEPTION_EXECUTE_HANDLER
|
|
: EXCEPTION_CONTINUE_SEARCH
|
|
) {
|
|
|
|
// failure
|
|
return CS_NO_MEMORY;
|
|
}
|
|
|
|
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 DBG
|
|
DeleteCriticalSection(&pLock->LockInfoLock);
|
|
#endif
|
|
return CC_INTERNAL_ERROR;
|
|
} else
|
|
return CC_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT DeleteLock( PLOCK pLock)
|
|
{
|
|
ASSERT(pLock != NULL);
|
|
|
|
#ifdef DBG
|
|
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 DBG
|
|
EnterCriticalSection(&pLock->LockInfoLock);
|
|
(pLock->wNumQueuedThreads)++;
|
|
LeaveCriticalSection(&pLock->LockInfoLock);
|
|
#endif
|
|
|
|
dwStatus = WaitForSingleObject(pLock->Lock, dwTimeout);
|
|
|
|
#ifdef DBG
|
|
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 DBG
|
|
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)Malloc(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 *)Malloc(pSource->wOctetStringLength);
|
|
if ((*ppDest)->pOctetString == NULL) {
|
|
Free(*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))
|
|
Free(pOctetString->pOctetString);
|
|
Free(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 *)Malloc(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;
|
|
Free(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)Malloc(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 *)Malloc(pSource->sData.wOctetStringLength);
|
|
if ((*ppDest)->sData.pOctetString == NULL) {
|
|
Free(*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))
|
|
Free(pNonStandardData->sData.pOctetString);
|
|
Free(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)Malloc(sizeof(CC_VENDORINFO));
|
|
if (*ppDest == NULL)
|
|
return CC_NO_MEMORY;
|
|
**ppDest = *pSource;
|
|
status = CopyOctetString(&(*ppDest)->pProductNumber, pSource->pProductNumber);
|
|
if (status != CC_OK) {
|
|
Free(*ppDest);
|
|
return status;
|
|
}
|
|
status = CopyOctetString(&(*ppDest)->pVersionNumber, pSource->pVersionNumber);
|
|
if (status != CC_OK) {
|
|
FreeOctetString((*ppDest)->pProductNumber);
|
|
Free(*ppDest);
|
|
return status;
|
|
}
|
|
return CC_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT FreeVendorInfo( PCC_VENDORINFO pVendorInfo)
|
|
{
|
|
if (pVendorInfo == NULL)
|
|
return CC_OK;
|
|
FreeOctetString(pVendorInfo->pProductNumber);
|
|
FreeOctetString(pVendorInfo->pVersionNumber);
|
|
Free(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)Malloc(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;
|
|
Free(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 *)Malloc((wcslen(pSource)+1)*sizeof(WCHAR));
|
|
if (*ppDest == NULL)
|
|
return CC_NO_MEMORY;
|
|
wcscpy(*ppDest, pSource);
|
|
return CC_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT FreeDisplay( PWSTR pszDisplay)
|
|
{
|
|
Free(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)Malloc(sizeof(CC_TERMCAPLIST));
|
|
if (*ppDest == NULL)
|
|
return CC_NO_MEMORY;
|
|
|
|
(*ppDest)->wLength = pSource->wLength;
|
|
(*ppDest)->pTermCapArray =
|
|
(PPCC_TERMCAP)Malloc(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)Malloc(sizeof(CC_TERMCAPDESCRIPTORS));
|
|
if (*ppDest == NULL)
|
|
return CC_NO_MEMORY;
|
|
|
|
(*ppDest)->wLength = pSource->wLength;
|
|
(*ppDest)->pTermCapDescriptorArray = (H245_TOTCAPDESC_T **)Malloc(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)Malloc(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 **)Malloc(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)
|
|
Free(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)
|
|
Free((*ppTermCapList)->pTermCapArray);
|
|
Free(*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)
|
|
Free(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)
|
|
Free((*ppTermCapDescriptors)->pTermCapDescriptorArray);
|
|
Free(*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)
|
|
Free(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)
|
|
Free(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)
|
|
Free(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 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)
|
|
Free((*ppSessionTable)->SessionInfoArray);
|
|
Free(*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) {
|
|
Free(CallList);
|
|
UnlockConference(pConference);
|
|
return status;
|
|
}
|
|
|
|
if (pCall->pQ931LocalConnectAddr == NULL) {
|
|
Free(CallList);
|
|
UnlockCall(pCall);
|
|
UnlockConference(pConference);
|
|
return CC_INTERNAL_ERROR;
|
|
}
|
|
|
|
if (pCall->pQ931LocalConnectAddr->nAddrType != CC_IP_BINARY) {
|
|
Free(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);
|
|
Free(CallList);
|
|
|
|
EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, TX_CHANNEL);
|
|
|
|
*ppSessionTable = (PCC_SESSIONTABLE)Malloc(sizeof(CC_SESSIONTABLE));
|
|
if (*ppSessionTable == NULL) {
|
|
Free(ChannelList);
|
|
UnlockConference(pConference);
|
|
return CC_NO_MEMORY;
|
|
}
|
|
(*ppSessionTable)->wLength = wNumChannels;
|
|
if (wNumChannels == 0)
|
|
(*ppSessionTable)->SessionInfoArray = NULL;
|
|
else {
|
|
(*ppSessionTable)->SessionInfoArray =
|
|
(PCC_SESSIONINFO)Malloc(sizeof(CC_SESSIONINFO) * wNumChannels);
|
|
if ((*ppSessionTable)->SessionInfoArray == NULL) {
|
|
Free(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 *)Malloc((*ppSessionTable)->SessionInfoArray[i].SessionDescription.wOctetStringLength);
|
|
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString == NULL) {
|
|
Free(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) {
|
|
Free((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
|
Free(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) {
|
|
Free((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
|
Free(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)Malloc(sizeof(CC_ADDR));
|
|
if ((*ppSessionTable)->SessionInfoArray[i].pRTPAddr == NULL) {
|
|
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
|
Free((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
|
Free(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)Malloc(sizeof(CC_ADDR));
|
|
if ((*ppSessionTable)->SessionInfoArray[i].pRTCPAddr == NULL) {
|
|
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
|
FreeAddr((*ppSessionTable)->SessionInfoArray[i].pRTPAddr);
|
|
Free((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
|
Free(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;
|
|
}
|
|
}
|
|
|
|
Free(ChannelList);
|
|
UnlockConference(pConference);
|
|
if (pbSessionTableChanged != NULL)
|
|
*pbSessionTableChanged = TRUE;
|
|
|
|
return CC_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT DefaultTermCapConstructor( CC_HCONFERENCE hConference,
|
|
DWORD 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)Malloc(sizeof(CC_TERMCAPLIST));
|
|
if (*ppOutTermCapList == NULL) {
|
|
Free(ChannelList);
|
|
UnlockConference(pConference);
|
|
return CC_NO_MEMORY;
|
|
}
|
|
(*ppOutTermCapList)->wLength = wNumChannels;
|
|
if (wNumChannels == 0)
|
|
(*ppOutTermCapList)->pTermCapArray = NULL;
|
|
else {
|
|
(*ppOutTermCapList)->pTermCapArray =
|
|
(PPCC_TERMCAP)Malloc(sizeof(PCC_TERMCAP) * wNumChannels);
|
|
if ((*ppOutTermCapList)->pTermCapArray == NULL) {
|
|
Free(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) {
|
|
Free(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) {
|
|
Free(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);
|
|
}
|
|
}
|
|
|
|
Free(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;
|
|
DWORD dwBandwidth;
|
|
|
|
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;
|
|
}
|
|
|
|
dwBandwidth = pCall->dwBandwidth;
|
|
|
|
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
|
|
dwBandwidth,
|
|
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
|
|
pCall->dwBandwidth,
|
|
#ifdef GATEKEEPER
|
|
pCall->GkiCall.usCRV); // CRV
|
|
#else
|
|
0); // CRV
|
|
#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 *)Malloc(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 *)Malloc(sizeof(unsigned short) * wStringLength);
|
|
if ((*pH245CommunicationTable)[i].pSessionDescription == NULL) {
|
|
for (j = 0; j < i; j++)
|
|
Free((*pH245CommunicationTable)[j].pSessionDescription);
|
|
Free(*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)
|
|
Free((*pH245CommunicationTable)[j].pSessionDescription);
|
|
Free(*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)
|
|
Free((*pH245CommunicationTable)[j].pSessionDescription);
|
|
Free(*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)Malloc(sizeof(CC_SESSIONTABLE));
|
|
if (*ppSessionTable == NULL)
|
|
return CC_NO_MEMORY;
|
|
|
|
(*ppSessionTable)->wLength = bCommunicationTableCount;
|
|
|
|
(*ppSessionTable)->SessionInfoArray = (PCC_SESSIONINFO)Malloc(sizeof(CC_SESSIONINFO) * bCommunicationTableCount);
|
|
if ((*ppSessionTable)->SessionInfoArray == NULL) {
|
|
Free(*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 *)Malloc(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)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
|
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
|
}
|
|
Free((*ppSessionTable)->SessionInfoArray);
|
|
Free(*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)
|
|
Free((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
|
for (j = 0; j < i; j++) {
|
|
H245FreeCap((*ppSessionTable)->SessionInfoArray[j].pTermCap);
|
|
if ((*ppSessionTable)->SessionInfoArray[j].pRTPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
|
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
|
}
|
|
Free((*ppSessionTable)->SessionInfoArray);
|
|
Free(*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)Malloc(sizeof(CC_ADDR));
|
|
if ((*ppSessionTable)->SessionInfoArray[i].pRTPAddr == NULL) {
|
|
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString != NULL)
|
|
Free((*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)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
|
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
|
}
|
|
Free((*ppSessionTable)->SessionInfoArray);
|
|
Free(*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)Malloc(sizeof(CC_ADDR));
|
|
if ((*ppSessionTable)->SessionInfoArray[i].pRTCPAddr == NULL) {
|
|
if ((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[i].SessionDescription.pOctetString);
|
|
H245FreeCap((*ppSessionTable)->SessionInfoArray[i].pTermCap);
|
|
if ((*ppSessionTable)->SessionInfoArray[i].pRTPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[i].pRTPAddr);
|
|
for (j = 0; j < i; j++) {
|
|
H245FreeCap((*ppSessionTable)->SessionInfoArray[j].pTermCap);
|
|
if ((*ppSessionTable)->SessionInfoArray[j].pRTPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTPAddr);
|
|
if ((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr != NULL)
|
|
Free((*ppSessionTable)->SessionInfoArray[j].pRTCPAddr);
|
|
}
|
|
Free((*ppSessionTable)->SessionInfoArray);
|
|
Free(*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)
|
|
Free(H245CommunicationTable[i].pSessionDescription);
|
|
Free(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 *)Malloc(sizeof(PCC_TERMCAPLIST) * (*pwListCount));
|
|
if (*ppTermCapList == NULL) {
|
|
Free(CallList);
|
|
return CC_NO_MEMORY;
|
|
}
|
|
|
|
*ppTermCapDescriptorList = (PCC_TERMCAPDESCRIPTORS *)Malloc(sizeof(PCC_TERMCAPDESCRIPTORS) * (*pwListCount));
|
|
if (*ppTermCapDescriptorList == NULL) {
|
|
Free(CallList);
|
|
Free(*ppTermCapList);
|
|
return CC_NO_MEMORY;
|
|
}
|
|
|
|
*pCallList = (PCALL *)Malloc(sizeof(PCALL) * (*pwListCount));
|
|
if (*pCallList == NULL) {
|
|
Free(CallList);
|
|
Free(*ppTermCapList);
|
|
Free(*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;
|
|
Free(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)
|
|
Free(pTermCapList);
|
|
if (pTermCapDescriptorList != NULL)
|
|
Free(pTermCapDescriptorList);
|
|
Free(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)Malloc(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;
|
|
Free(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;
|
|
|
|
Free(pQueueItem);
|
|
return CC_OK;
|
|
}
|