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