910 lines
27 KiB
C++
910 lines
27 KiB
C++
/****************************************************************************
|
|
*
|
|
* $Archive: S:/STURGEON/SRC/Q931/VCS/hcall.cpv $
|
|
*
|
|
* 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-1996 Intel Corporation.
|
|
*
|
|
* $Revision: 2.7.1.0 $
|
|
* $Date: 20 Jun 1997 14:12:08 $
|
|
* $Author: MANDREWS $
|
|
*
|
|
* Deliverable:
|
|
*
|
|
* Abstract:
|
|
*
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
#pragma warning ( disable : 4100 4115 4201 4214 4514 4702 4710 )
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "q931asn.h"
|
|
|
|
#include "isrg.h"
|
|
|
|
#include "common.h"
|
|
#include "q931.h"
|
|
|
|
#include "hcall.h"
|
|
#include "utils.h"
|
|
|
|
#include "tstable.h"
|
|
#include "provider.h"
|
|
|
|
#ifdef UNICODE_TRACE
|
|
// We include this header to fix problems with macro expansion when Unicode is turned on.
|
|
#include "unifix.h"
|
|
#endif
|
|
|
|
static BOOL bCallListCreated = FALSE;
|
|
|
|
// Pointer to our global table. Note that this table replaces the previous
|
|
// linked-list implementation.
|
|
|
|
TSTable<CALL_OBJECT>* gpCallObjectTable = NULL;
|
|
|
|
// Our call back function for enumerating the table when we want to tear down
|
|
// all existing calls
|
|
|
|
DWORD Q931HangUpAllCalls(P_CALL_OBJECT pCallObject, LPVOID context);
|
|
|
|
// Our call back function for determining if a timer has expired
|
|
|
|
DWORD Q931CheckForTimeout(P_CALL_OBJECT pCallObject, LPVOID context);
|
|
|
|
// Our call back function for determining if a timer has expired
|
|
|
|
DWORD Q931CallObjectFind(P_CALL_OBJECT pCallObject, LPVOID context);
|
|
|
|
|
|
static struct
|
|
{
|
|
WORD wCRV; // Call Reference Value (0..7FFF).
|
|
CRITICAL_SECTION Lock;
|
|
} CRVSource;
|
|
|
|
static struct
|
|
{
|
|
BOOL bBusy;
|
|
DWORD dwTimerCount;
|
|
DWORD dwTicks301;
|
|
DWORD dwTicks303;
|
|
UINT_PTR uTimerId;
|
|
CRITICAL_SECTION Lock;
|
|
} Q931GlobalTimer = {0};
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
BOOL bFound;
|
|
WORD wCRV;
|
|
PCC_ADDR pPeerAddr;
|
|
HQ931CALL hQ931Call;
|
|
} Q931CALLOBJKEY, *PQ931CALLOBJKEY;
|
|
|
|
|
|
//====================================================================================
|
|
//
|
|
// PRIVATE FUNCTIONS
|
|
//
|
|
//====================================================================================
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
Q931CRVNew(
|
|
WORD *pwCRV)
|
|
{
|
|
EnterCriticalSection(&(CRVSource.Lock));
|
|
CRVSource.wCRV = (WORD)((CRVSource.wCRV + 1) & 0x7fff);
|
|
if (CRVSource.wCRV == 0)
|
|
{
|
|
CRVSource.wCRV = 1;
|
|
}
|
|
*pwCRV = CRVSource.wCRV;
|
|
LeaveCriticalSection(&(CRVSource.Lock));
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//
|
|
// PUBLIC FUNCTIONS
|
|
//
|
|
//====================================================================================
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallListCreate()
|
|
{
|
|
if (bCallListCreated == TRUE)
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_DUPLICATE_INITIALIZE;
|
|
}
|
|
|
|
// list creation is not protected against multiple threads because it is only
|
|
// called when a process is started, not when a thread is started.
|
|
|
|
// Create the call object table. We will initially create 30 entries. The
|
|
// TSTable can automatically grow, so no worrying about running out of entries.
|
|
|
|
gpCallObjectTable = new TSTable <CALL_OBJECT> (30);
|
|
|
|
if (gpCallObjectTable == NULL || gpCallObjectTable->IsInitialized() == FALSE)
|
|
{
|
|
return CS_NO_MEMORY;
|
|
}
|
|
|
|
__try {
|
|
|
|
CRVSource.wCRV = (WORD) (time(NULL) & 0x7fff);
|
|
InitializeCriticalSectionAndSpinCount(&(CRVSource.Lock),H323_SPIN_COUNT);
|
|
|
|
Q931GlobalTimer.dwTicks301 = Q931_TICKS_301;
|
|
Q931GlobalTimer.dwTicks303 = Q931_TICKS_303;
|
|
InitializeCriticalSectionAndSpinCount(&(Q931GlobalTimer.Lock),H323_SPIN_COUNT);
|
|
|
|
} __except ((GetExceptionCode() == STATUS_NO_MEMORY)
|
|
? EXCEPTION_EXECUTE_HANDLER
|
|
: EXCEPTION_CONTINUE_SEARCH
|
|
) {
|
|
|
|
// failure
|
|
return CS_NO_MEMORY;
|
|
}
|
|
|
|
bCallListCreated = TRUE;
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
|
|
//====================================================================================
|
|
// this routine assumes all of the events and sockets belonging to each object
|
|
// are already destroyed. It just makes sure memory is cleaned up.
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallListDestroy()
|
|
{
|
|
if (bCallListCreated == FALSE)
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_INTERNAL_ERROR;
|
|
}
|
|
|
|
// For all entries, hang up the calls
|
|
|
|
gpCallObjectTable->EnumerateEntries(Q931HangUpAllCalls,
|
|
NULL);
|
|
|
|
// Get rid of the call object table
|
|
|
|
delete gpCallObjectTable;
|
|
gpCallObjectTable = NULL;
|
|
|
|
DeleteCriticalSection(&(Q931GlobalTimer.Lock));
|
|
DeleteCriticalSection(&(CRVSource.Lock));
|
|
|
|
bCallListCreated = FALSE;
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
void
|
|
CallObjectFree(P_CALL_OBJECT pCallObject)
|
|
{
|
|
if (pCallObject->NonStandardData.sData.pOctetString != NULL)
|
|
{
|
|
Free(pCallObject->NonStandardData.sData.pOctetString);
|
|
pCallObject->NonStandardData.sData.pOctetString = NULL;
|
|
}
|
|
if (pCallObject->VendorInfoPresent)
|
|
{
|
|
if (pCallObject->VendorInfo.pProductNumber != NULL)
|
|
{
|
|
Free(pCallObject->VendorInfo.pProductNumber);
|
|
}
|
|
if (pCallObject->VendorInfo.pVersionNumber != NULL)
|
|
{
|
|
Free(pCallObject->VendorInfo.pVersionNumber);
|
|
}
|
|
}
|
|
|
|
Q931FreeAliasNames(pCallObject->pCallerAliasList);
|
|
pCallObject->pCallerAliasList = NULL;
|
|
Q931FreeAliasNames(pCallObject->pCalleeAliasList);
|
|
pCallObject->pCalleeAliasList = NULL;
|
|
Q931FreeAliasNames(pCallObject->pExtraAliasList);
|
|
pCallObject->pExtraAliasList = NULL;
|
|
Q931FreeAliasItem(pCallObject->pExtensionAliasItem);
|
|
pCallObject->pExtensionAliasItem = NULL;
|
|
Free(pCallObject);
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallObjectCreate(
|
|
PHQ931CALL phQ931Call,
|
|
DWORD dwListenToken,
|
|
DWORD dwUserToken,
|
|
Q931_CALLBACK ConnectCallback,
|
|
BOOL fIsCaller,
|
|
CC_ADDR *pLocalAddr, // Local address on which channel is connected
|
|
CC_ADDR *pPeerConnectAddr, // Address to which channel is connected
|
|
CC_ADDR *pPeerCallAddr, // Address of opposite call end-point.
|
|
CC_ADDR *pSourceAddr, // Address of this call end-point.
|
|
CC_CONFERENCEID *pConferenceID,
|
|
WORD wGoal,
|
|
WORD wCallType,
|
|
BOOL bCallerIsMC,
|
|
char *pszDisplay,
|
|
char *pszCalledPartyNumber,
|
|
PCC_ALIASNAMES pCallerAliasList,
|
|
PCC_ALIASNAMES pCalleeAliasList,
|
|
PCC_ALIASNAMES pExtraAliasList,
|
|
PCC_ALIASITEM pExtensionAliasItem,
|
|
PCC_ENDPOINTTYPE pEndpointType,
|
|
PCC_NONSTANDARDDATA pNonStandardData, // questionable!
|
|
DWORD dwBandwidth,
|
|
WORD wCRV)
|
|
{
|
|
P_CALL_OBJECT pCallObject = NULL;
|
|
CS_STATUS status = CS_OK;
|
|
CS_STATUS CopyStatus = CS_OK;
|
|
DWORD dwIndex = 0;
|
|
int rc = 0;
|
|
|
|
// make sure the call list has been created.
|
|
if (bCallListCreated == FALSE)
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_INTERNAL_ERROR;
|
|
}
|
|
|
|
// validate all parameters for bogus values.
|
|
if ((phQ931Call == NULL) || (ConnectCallback == NULL))
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
// set phQ931Call now, in case we encounter an error later.
|
|
*phQ931Call = 0;
|
|
|
|
pCallObject = (P_CALL_OBJECT)Malloc(sizeof(CALL_OBJECT));
|
|
if (pCallObject == NULL)
|
|
{
|
|
return CS_NO_MEMORY;
|
|
}
|
|
memset(pCallObject, 0, sizeof(CALL_OBJECT));
|
|
|
|
|
|
// create and init an oss world struct for each call object. This is
|
|
// necessary to work in MT environments.
|
|
rc = Q931_InitWorld(&pCallObject->World);
|
|
if (rc != ASN1_SUCCESS)
|
|
{
|
|
Q931DBG((DBGERROR, "Q931_InitCoder() returned: %d ", rc));
|
|
return CS_SUBSYSTEM_FAILURE;
|
|
}
|
|
|
|
pCallObject->LocalAddr.bMulticast = FALSE;
|
|
pCallObject->PeerConnectAddr.bMulticast = FALSE;
|
|
pCallObject->PeerCallAddr.bMulticast = FALSE;
|
|
pCallObject->SourceAddr.bMulticast = FALSE;
|
|
|
|
|
|
if (wCRV == 0)
|
|
{
|
|
if (Q931CRVNew(&pCallObject->wCRV) != CS_OK)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CS_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCallObject->wCRV = wCRV;
|
|
}
|
|
|
|
pCallObject->szDisplay[0] = '\0';
|
|
if (pszDisplay)
|
|
{
|
|
strcpy(pCallObject->szDisplay, pszDisplay);
|
|
}
|
|
|
|
pCallObject->szCalledPartyNumber[0] = '\0';
|
|
if (pszCalledPartyNumber)
|
|
{
|
|
strcpy(pCallObject->szCalledPartyNumber, pszCalledPartyNumber);
|
|
}
|
|
|
|
pCallObject->dwListenToken = dwListenToken;
|
|
pCallObject->dwUserToken = dwUserToken;
|
|
pCallObject->Callback = ConnectCallback;
|
|
pCallObject->bCallState = CALLSTATE_NULL;
|
|
pCallObject->fIsCaller = fIsCaller;
|
|
|
|
if (pLocalAddr)
|
|
{
|
|
pCallObject->LocalAddr = *pLocalAddr;
|
|
}
|
|
if (pPeerConnectAddr)
|
|
{
|
|
pCallObject->PeerConnectAddr = *pPeerConnectAddr;
|
|
}
|
|
if (pPeerCallAddr)
|
|
{
|
|
pCallObject->PeerCallAddr = *pPeerCallAddr;
|
|
pCallObject->PeerCallAddrPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pCallObject->PeerCallAddrPresent = FALSE;
|
|
}
|
|
|
|
if (pSourceAddr)
|
|
{
|
|
pCallObject->SourceAddr = *pSourceAddr;
|
|
pCallObject->SourceAddrPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pCallObject->SourceAddrPresent = FALSE;
|
|
}
|
|
|
|
if (pConferenceID == NULL)
|
|
{
|
|
memset(&(pCallObject->ConferenceID), 0, sizeof(CC_CONFERENCEID));
|
|
}
|
|
else
|
|
{
|
|
int length = min(sizeof(pConferenceID->buffer),
|
|
sizeof(pCallObject->ConferenceID.buffer));
|
|
memcpy(pCallObject->ConferenceID.buffer,
|
|
pConferenceID->buffer, length);
|
|
}
|
|
|
|
pCallObject->wGoal = wGoal;
|
|
pCallObject->bCallerIsMC = bCallerIsMC;
|
|
pCallObject->wCallType = wCallType;
|
|
|
|
if (pNonStandardData != NULL)
|
|
{
|
|
pCallObject->NonStandardData = *pNonStandardData;
|
|
if (pNonStandardData->sData.wOctetStringLength > 0)
|
|
{
|
|
pCallObject->NonStandardData.sData.pOctetString =
|
|
(BYTE *) Malloc(pNonStandardData->sData.wOctetStringLength);
|
|
if (pCallObject->NonStandardData.sData.pOctetString == NULL)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CS_NO_MEMORY;
|
|
}
|
|
memcpy(pCallObject->NonStandardData.sData.pOctetString,
|
|
pNonStandardData->sData.pOctetString,
|
|
pNonStandardData->sData.wOctetStringLength);
|
|
}
|
|
pCallObject->NonStandardDataPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pCallObject->NonStandardDataPresent = FALSE;
|
|
}
|
|
|
|
CopyStatus = Q931CopyAliasNames(&(pCallObject->pCallerAliasList),
|
|
pCallerAliasList);
|
|
if (CopyStatus != CS_OK)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CopyStatus;
|
|
}
|
|
CopyStatus = Q931CopyAliasNames(&(pCallObject->pCalleeAliasList),
|
|
pCalleeAliasList);
|
|
if (CopyStatus != CS_OK)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CopyStatus;
|
|
}
|
|
CopyStatus = Q931CopyAliasNames(&(pCallObject->pExtraAliasList),
|
|
pExtraAliasList);
|
|
if (CopyStatus != CS_OK)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CopyStatus;
|
|
}
|
|
CopyStatus = Q931CopyAliasItem(&(pCallObject->pExtensionAliasItem),
|
|
pExtensionAliasItem);
|
|
if (CopyStatus != CS_OK)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CopyStatus;
|
|
}
|
|
|
|
pCallObject->bResolved = FALSE;
|
|
pCallObject->VendorInfoPresent = FALSE;
|
|
pCallObject->bIsTerminal = TRUE;
|
|
pCallObject->bIsGateway = FALSE;
|
|
if (pEndpointType != NULL)
|
|
{
|
|
PCC_VENDORINFO pVendorInfo = pEndpointType->pVendorInfo;
|
|
if (pVendorInfo != NULL)
|
|
{
|
|
pCallObject->VendorInfoPresent = TRUE;
|
|
pCallObject->VendorInfo = *(pVendorInfo);
|
|
|
|
if (pVendorInfo->pProductNumber && pVendorInfo->pProductNumber->pOctetString &&
|
|
pVendorInfo->pProductNumber->wOctetStringLength)
|
|
{
|
|
memcpy(pCallObject->bufVendorProduct,
|
|
pVendorInfo->pProductNumber->pOctetString,
|
|
pVendorInfo->pProductNumber->wOctetStringLength);
|
|
pCallObject->VendorInfo.pProductNumber = (CC_OCTETSTRING*) Malloc(sizeof(CC_OCTETSTRING));
|
|
if (pCallObject->VendorInfo.pProductNumber == NULL)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CS_NO_MEMORY;
|
|
}
|
|
pCallObject->VendorInfo.pProductNumber->pOctetString =
|
|
pCallObject->bufVendorProduct;
|
|
pCallObject->VendorInfo.pProductNumber->wOctetStringLength =
|
|
pVendorInfo->pProductNumber->wOctetStringLength;
|
|
}
|
|
else
|
|
{
|
|
pCallObject->VendorInfo.pProductNumber = NULL;
|
|
}
|
|
|
|
if (pVendorInfo->pVersionNumber && pVendorInfo->pVersionNumber->pOctetString &&
|
|
pVendorInfo->pVersionNumber->wOctetStringLength)
|
|
{
|
|
memcpy(pCallObject->bufVendorVersion,
|
|
pVendorInfo->pVersionNumber->pOctetString,
|
|
pVendorInfo->pVersionNumber->wOctetStringLength);
|
|
pCallObject->VendorInfo.pVersionNumber = (CC_OCTETSTRING*) Malloc(sizeof(CC_OCTETSTRING));
|
|
if (pCallObject->VendorInfo.pVersionNumber == NULL)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CS_NO_MEMORY;
|
|
}
|
|
pCallObject->VendorInfo.pVersionNumber->pOctetString =
|
|
pCallObject->bufVendorVersion;
|
|
pCallObject->VendorInfo.pVersionNumber->wOctetStringLength =
|
|
pVendorInfo->pVersionNumber->wOctetStringLength;
|
|
}
|
|
else
|
|
{
|
|
pCallObject->VendorInfo.pVersionNumber = NULL;
|
|
}
|
|
|
|
}
|
|
pCallObject->bIsTerminal = pEndpointType->bIsTerminal;
|
|
pCallObject->bIsGateway = pEndpointType->bIsGateway;
|
|
pCallObject->dwBandwidth = dwBandwidth;
|
|
}
|
|
|
|
Q931MakePhysicalID(&pCallObject->dwPhysicalId);
|
|
|
|
// Insert the object into the table...if that doesn't work, blow away the object.
|
|
|
|
if (gpCallObjectTable->CreateAndLock(pCallObject,
|
|
&dwIndex) == FALSE)
|
|
{
|
|
CallObjectFree(pCallObject);
|
|
return CS_INTERNAL_ERROR;
|
|
}
|
|
|
|
// Save the index as the handle (this makes it easier to find the object later).
|
|
|
|
*phQ931Call = pCallObject->hQ931Call = (HQ931CALL) dwIndex;
|
|
Q931DBG((DBGTRACE, "CallObjectCreate() -returned-> 0x%08x", dwIndex));
|
|
// Unlock the entry
|
|
|
|
gpCallObjectTable->Unlock(dwIndex);
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallObjectDestroy(
|
|
P_CALL_OBJECT pCallObject)
|
|
{
|
|
if (pCallObject == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
Q931DBG((DBGTRACE, "CallObjectDestroy(0x%08lx)", pCallObject->hQ931Call));
|
|
|
|
Q931_TermWorld(&pCallObject->World);
|
|
|
|
// Since the caller must already have a lock on the object, remove the entry from
|
|
// the table. We won't let the table delete the object as we want to clean up.
|
|
|
|
if (gpCallObjectTable->Delete((DWORD) pCallObject->hQ931Call) == FALSE)
|
|
{
|
|
return CS_OK;
|
|
}
|
|
|
|
Q931StopTimer(pCallObject, Q931_TIMER_301);
|
|
Q931StopTimer(pCallObject, Q931_TIMER_303);
|
|
|
|
// Unlock the object
|
|
|
|
gpCallObjectTable->Unlock((DWORD) pCallObject->hQ931Call);
|
|
|
|
// Free up the call object
|
|
|
|
CallObjectFree(pCallObject);
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallObjectLock(
|
|
HQ931CALL hQ931Call,
|
|
PP_CALL_OBJECT ppCallObject)
|
|
{
|
|
if (ppCallObject == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
// Attempt to lock the entry. If that fails, we'll return CS_BAD_PARAM under
|
|
// the assumption that the entry is invalid.
|
|
|
|
*ppCallObject = gpCallObjectTable->Lock((DWORD) hQ931Call);
|
|
|
|
return (*ppCallObject == NULL ? CS_BAD_PARAM : CS_OK);
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallObjectUnlock(
|
|
P_CALL_OBJECT pCallObject)
|
|
{
|
|
if (pCallObject == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
// Unlock the entry
|
|
|
|
if (gpCallObjectTable->Unlock((DWORD) pCallObject->hQ931Call) == FALSE)
|
|
{
|
|
Q931DBG((DBGERROR, "gpCallObjectTable->Unlock(0x%08lx) FAILED!!!!", pCallObject->hQ931Call));
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
CallObjectValidate(
|
|
HQ931CALL hQ931Call)
|
|
{
|
|
if (gpCallObjectTable->Validate((DWORD) hQ931Call) == TRUE)
|
|
{
|
|
return CS_OK;
|
|
}
|
|
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
BOOL
|
|
CallObjectFind(
|
|
HQ931CALL *phQ931Call,
|
|
WORD wCRV,
|
|
PCC_ADDR pPeerAddr)
|
|
{
|
|
Q931CALLOBJKEY Q931CallObjKey;
|
|
Q931CallObjKey.wCRV = wCRV;
|
|
Q931CallObjKey.pPeerAddr = pPeerAddr;
|
|
Q931CallObjKey.bFound = FALSE;
|
|
|
|
gpCallObjectTable->EnumerateEntries(Q931CallObjectFind,
|
|
(LPVOID) &Q931CallObjKey);
|
|
|
|
if(Q931CallObjKey.bFound == TRUE)
|
|
{
|
|
*phQ931Call = Q931CallObjKey.hQ931Call;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS CallObjectMarkForDelete(HQ931CALL hQ931Call)
|
|
{
|
|
// User must have the object already locked to call this.
|
|
|
|
// Mark the object as deleted but don't let the table delete the object's
|
|
// memory.
|
|
|
|
return (gpCallObjectTable->Delete((DWORD) hQ931Call) == FALSE ? CS_BAD_PARAM : CS_OK);
|
|
}
|
|
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Timer Routines...
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
//====================================================================================
|
|
// This routine will be called every 1000 ms if any call object
|
|
// has caused the Q931GlobalTimer to be created.
|
|
//====================================================================================
|
|
VOID CALLBACK
|
|
Q931TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
|
|
{
|
|
DWORD dwTickCount = GetTickCount();
|
|
|
|
EnterCriticalSection(&(Q931GlobalTimer.Lock));
|
|
if (Q931GlobalTimer.bBusy)
|
|
{
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
return;
|
|
}
|
|
Q931GlobalTimer.bBusy = TRUE;
|
|
|
|
// Check all of the entries for timeout
|
|
|
|
gpCallObjectTable->EnumerateEntries(Q931CheckForTimeout,
|
|
(LPVOID) &dwTickCount);
|
|
|
|
Q931GlobalTimer.bBusy = FALSE;
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
HRESULT
|
|
Q931StartTimer(P_CALL_OBJECT pCallObject, DWORD wTimerId)
|
|
{
|
|
if (pCallObject == NULL)
|
|
{
|
|
return CS_BAD_PARAM;
|
|
}
|
|
|
|
switch (wTimerId)
|
|
{
|
|
case Q931_TIMER_301:
|
|
if (pCallObject->dwTimerAlarm301)
|
|
{
|
|
// timer is already set for this call object...
|
|
return CS_INTERNAL_ERROR;
|
|
}
|
|
EnterCriticalSection(&(Q931GlobalTimer.Lock));
|
|
pCallObject->dwTimerAlarm301 = GetTickCount() + Q931GlobalTimer.dwTicks301;
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
break;
|
|
case Q931_TIMER_303:
|
|
if (pCallObject->dwTimerAlarm303)
|
|
{
|
|
// timer is already set for this call object...
|
|
return CS_INTERNAL_ERROR;
|
|
}
|
|
EnterCriticalSection(&(Q931GlobalTimer.Lock));
|
|
pCallObject->dwTimerAlarm303 = GetTickCount() + Q931GlobalTimer.dwTicks303;
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
break;
|
|
default:
|
|
return CS_BAD_PARAM;
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(&(Q931GlobalTimer.Lock));
|
|
if (!Q931GlobalTimer.dwTimerCount)
|
|
{
|
|
Q931GlobalTimer.uTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)Q931TimerProc);
|
|
}
|
|
Q931GlobalTimer.dwTimerCount++;
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
HRESULT
|
|
Q931StopTimer(P_CALL_OBJECT pCallObject, DWORD wTimerId)
|
|
{
|
|
if (pCallObject == NULL)
|
|
{
|
|
return CS_BAD_PARAM;
|
|
}
|
|
switch (wTimerId)
|
|
{
|
|
case Q931_TIMER_301:
|
|
if (!pCallObject->dwTimerAlarm301)
|
|
{
|
|
return CS_OK;
|
|
}
|
|
pCallObject->dwTimerAlarm301 = 0;
|
|
break;
|
|
case Q931_TIMER_303:
|
|
if (!pCallObject->dwTimerAlarm303)
|
|
{
|
|
return CS_OK;
|
|
}
|
|
pCallObject->dwTimerAlarm303 = 0;
|
|
break;
|
|
default:
|
|
return CS_BAD_PARAM;
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(&(Q931GlobalTimer.Lock));
|
|
if (Q931GlobalTimer.dwTimerCount > 0)
|
|
{
|
|
Q931GlobalTimer.dwTimerCount--;
|
|
if (!Q931GlobalTimer.dwTimerCount)
|
|
{
|
|
KillTimer(NULL, Q931GlobalTimer.uTimerId);
|
|
Q931GlobalTimer.uTimerId = 0;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
CS_STATUS
|
|
Q931SetAlertingTimeout(DWORD dwDuration)
|
|
{
|
|
EnterCriticalSection(&(Q931GlobalTimer.Lock));
|
|
if (dwDuration)
|
|
{
|
|
Q931GlobalTimer.dwTicks303 = dwDuration;
|
|
}
|
|
else
|
|
{
|
|
Q931GlobalTimer.dwTicks303 = Q931_TICKS_303;
|
|
}
|
|
LeaveCriticalSection(&(Q931GlobalTimer.Lock));
|
|
return CS_OK;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
DWORD Q931HangUpAllCalls(P_CALL_OBJECT pCallObject, LPVOID context)
|
|
{
|
|
HQ931CALL hQ931Call = pCallObject->hQ931Call;
|
|
|
|
// Try to hangup the call object.
|
|
|
|
Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
|
|
|
|
// Try to lock the object. If that succeeds, then we want to force the object to
|
|
// be deleted. We should never have to do this as the hang up is supposed to
|
|
// take care of that for us.
|
|
|
|
if (gpCallObjectTable->Lock(hQ931Call) != NULL)
|
|
{
|
|
CallObjectDestroy(pCallObject);
|
|
}
|
|
|
|
return CALLBACK_DELETE_ENTRY;
|
|
}
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
DWORD
|
|
Q931CallObjectFind(P_CALL_OBJECT pCallObject, LPVOID context)
|
|
{
|
|
PQ931CALLOBJKEY pQ931CallObjKey = (PQ931CALLOBJKEY) context;
|
|
PCC_ADDR pPeerAddr = pQ931CallObjKey->pPeerAddr;
|
|
WORD wCRV = pQ931CallObjKey->wCRV;
|
|
|
|
if (!pCallObject->bResolved)
|
|
{
|
|
return(CALLBACK_CONTINUE);
|
|
}
|
|
|
|
if ((pCallObject->wCRV & (~0x8000)) == (wCRV & (~0x8000)))
|
|
{
|
|
if (!pPeerAddr)
|
|
{
|
|
pQ931CallObjKey->bFound = TRUE;
|
|
pQ931CallObjKey->hQ931Call = pCallObject->hQ931Call;
|
|
return(CALLBACK_ABORT);
|
|
}
|
|
else if ((pPeerAddr->nAddrType == CC_IP_BINARY) &&
|
|
(pPeerAddr->Addr.IP_Binary.dwAddr == INADDR_LOOPBACK))
|
|
{
|
|
pQ931CallObjKey->bFound = FALSE;
|
|
pQ931CallObjKey->hQ931Call = NULL;
|
|
return(CALLBACK_CONTINUE); // allow loopback calls
|
|
}
|
|
else if ((pCallObject->LocalAddr.nAddrType == CC_IP_BINARY) &&
|
|
(pPeerAddr->nAddrType == CC_IP_BINARY) &&
|
|
(pCallObject->LocalAddr.Addr.IP_Binary.dwAddr == pPeerAddr->Addr.IP_Binary.dwAddr))
|
|
{
|
|
pQ931CallObjKey->bFound = FALSE;
|
|
pQ931CallObjKey->hQ931Call = NULL;
|
|
return(CALLBACK_CONTINUE); // allow loopback calls
|
|
}
|
|
else if ((pCallObject->PeerConnectAddr.nAddrType == CC_IP_BINARY) &&
|
|
(pPeerAddr->nAddrType == CC_IP_BINARY) &&
|
|
(pCallObject->PeerConnectAddr.Addr.IP_Binary.dwAddr == pPeerAddr->Addr.IP_Binary.dwAddr))
|
|
{
|
|
pQ931CallObjKey->bFound = TRUE;
|
|
pQ931CallObjKey->hQ931Call = pCallObject->hQ931Call;
|
|
return(CALLBACK_ABORT);
|
|
}
|
|
}
|
|
return(CALLBACK_CONTINUE);
|
|
}
|
|
|
|
|
|
//====================================================================================
|
|
//====================================================================================
|
|
|
|
DWORD Q931CheckForTimeout(P_CALL_OBJECT pCallObject, LPVOID context)
|
|
{
|
|
DWORD dwTickCount = *((LPDWORD) context);
|
|
|
|
// Determine if a timer has expired for the entry
|
|
|
|
if (pCallObject->dwTimerAlarm301 &&
|
|
(pCallObject->dwTimerAlarm301 <= dwTickCount))
|
|
{
|
|
Q931StopTimer(pCallObject, Q931_TIMER_301);
|
|
Q931StopTimer(pCallObject, Q931_TIMER_303);
|
|
|
|
if (pCallObject->dwTimerAlarm303 &&
|
|
(pCallObject->dwTimerAlarm303 < pCallObject->dwTimerAlarm301) &&
|
|
(pCallObject->dwTimerAlarm303 <= dwTickCount))
|
|
{
|
|
CallBackT303(pCallObject);
|
|
}
|
|
else
|
|
{
|
|
CallBackT301(pCallObject);
|
|
}
|
|
}
|
|
else if (pCallObject->dwTimerAlarm303 &&
|
|
(pCallObject->dwTimerAlarm303 <= dwTickCount))
|
|
{
|
|
Q931StopTimer(pCallObject, Q931_TIMER_301);
|
|
Q931StopTimer(pCallObject, Q931_TIMER_303);
|
|
CallBackT303(pCallObject);
|
|
}
|
|
|
|
return CALLBACK_CONTINUE;
|
|
}
|