|
|
/****************************************************************************
* * $Archive: S:/STURGEON/SRC/Q931/VCS/q931.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-1996 Intel Corporation. * * $Revision: 1.122.1.0 $ * $Date: 20 Jun 1997 14:12:46 $ * $Author: MANDREWS $ * * BCL's revision info: * Revision: 1.99 * Date: 19 Nov 1996 14:54:02 * Author: rodellx * * Deliverable: * * Abstract: * * * Notes: * ***************************************************************************/ // [ ] Add facility ie to FACILITY MSG.
// [ ] Read Q931 Appendix D.
#pragma warning ( disable : 4057 4100 4115 4201 4214 4514 )
#ifdef __cplusplus
extern "C" { #endif
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <rpc.h>
#include "apierror.h"
#include "isrg.h"
#include "incommon.h"
#include "linkapi.h"
#include "common.h"
#include "q931.h"
#include "utils.h"
#include "hlisten.h"
#include "hcall.h"
#include "q931pdu.h"
#include "provider.h"
#if (defined(_DEBUG) && defined(PCS_COMPLIANCE))
#include "interop.h"
#include "q931plog.h"
LPInteropLogger Q931Logger; #endif
#define RECEIVE_BUFFER_SIZE 0x2000
#define HANGUP_TIMEOUT 1000 // 1 second
#define CANCEL_LISTEN_TIMEOUT 5000 // 5 seconds
// variable needed to support ISR debug facility.
#if (ISRDEBUGINFO >= 1)
WORD ghISRInst = 0; #endif
#ifdef UNICODE_TRACE
// We include this header to fix problems with macro expansion when Unicode is turned on.
#include "unifix.h"
#endif
#define _Unicode(x) L ## x
#define Unicode(x) _Unicode(x)
// global data used by WinSock.
static BOOL bQ931Initialized = FALSE;
static Q931_RECEIVE_PDU_CALLBACK gReceivePDUHookProc = NULL;
static struct { DWORD TempID; CC_CONFERENCEID ConferenceID; CRITICAL_SECTION Lock; } ConferenceIDSource;
//====================================================================================
//
// PRIVATE FUNCTIONS
//
//====================================================================================
//====================================================================================
//====================================================================================
void _FreeSetupASN(Q931_SETUP_ASN *pSetupASN) { ASSERT(pSetupASN != NULL);
// Cleanup any dynamically allocated fields within SetupASN
if (pSetupASN->NonStandardData.sData.pOctetString) { Free(pSetupASN->NonStandardData.sData.pOctetString); pSetupASN->NonStandardData.sData.pOctetString = NULL; } if (pSetupASN->VendorInfo.pProductNumber) { Free(pSetupASN->VendorInfo.pProductNumber); pSetupASN->VendorInfo.pProductNumber = NULL; } if (pSetupASN->VendorInfo.pVersionNumber) { Free(pSetupASN->VendorInfo.pVersionNumber); pSetupASN->VendorInfo.pVersionNumber = NULL; } Q931FreeAliasNames(pSetupASN->pCallerAliasList); pSetupASN->pCallerAliasList = NULL; Q931FreeAliasNames(pSetupASN->pCalleeAliasList); pSetupASN->pCalleeAliasList = NULL; Q931FreeAliasNames(pSetupASN->pExtraAliasList); pSetupASN->pExtraAliasList = NULL; Q931FreeAliasItem(pSetupASN->pExtensionAliasItem); pSetupASN->pExtensionAliasItem = NULL; }
void _FreeReleaseCompleteASN(Q931_RELEASE_COMPLETE_ASN *pReleaseCompleteASN) { ASSERT(pReleaseCompleteASN != NULL);
// Cleanup any dynamically allocated fields within SetupASN
if (pReleaseCompleteASN->NonStandardData.sData.pOctetString) { Free(pReleaseCompleteASN->NonStandardData.sData.pOctetString); pReleaseCompleteASN->NonStandardData.sData.pOctetString = NULL; } }
void _FreeFacilityASN(Q931_FACILITY_ASN *pFacilityASN) { ASSERT(pFacilityASN != NULL);
// Cleanup any dynamically allocated fields within SetupASN
if (pFacilityASN->NonStandardData.sData.pOctetString) { Free(pFacilityASN->NonStandardData.sData.pOctetString); pFacilityASN->NonStandardData.sData.pOctetString = NULL; } }
void _FreeProceedingASN(Q931_CALL_PROCEEDING_ASN *pProceedingASN) { ASSERT(pProceedingASN != NULL);
// Cleanup any dynamically allocated fields within SetupASN
if (pProceedingASN->NonStandardData.sData.pOctetString) { Free(pProceedingASN->NonStandardData.sData.pOctetString); pProceedingASN->NonStandardData.sData.pOctetString = NULL; } }
void _FreeAlertingASN(Q931_ALERTING_ASN *pAlertingASN) { ASSERT(pAlertingASN != NULL);
// Cleanup any dynamically allocated fields within SetupASN
if (pAlertingASN->NonStandardData.sData.pOctetString) { Free(pAlertingASN->NonStandardData.sData.pOctetString); pAlertingASN->NonStandardData.sData.pOctetString = NULL; } }
void _FreeConnectASN(Q931_CONNECT_ASN *pConnectASN) { ASSERT(pConnectASN != NULL);
// Cleanup any dynamically allocated fields within SetupASN
if (pConnectASN->NonStandardData.sData.pOctetString) { Free(pConnectASN->NonStandardData.sData.pOctetString); pConnectASN->NonStandardData.sData.pOctetString = NULL; } if (pConnectASN->VendorInfo.pProductNumber) { Free(pConnectASN->VendorInfo.pProductNumber); pConnectASN->VendorInfo.pProductNumber = NULL; } if (pConnectASN->VendorInfo.pVersionNumber) { Free(pConnectASN->VendorInfo.pVersionNumber); pConnectASN->VendorInfo.pVersionNumber = NULL; } }
void _ConferenceIDNew( CC_CONFERENCEID *pConferenceID) { UUID id; int iresult; EnterCriticalSection(&(ConferenceIDSource.Lock));
memset(ConferenceIDSource.ConferenceID.buffer, 0, sizeof(ConferenceIDSource.ConferenceID.buffer)); iresult = UuidCreate(&id); if ((iresult == RPC_S_OK) || (iresult ==RPC_S_UUID_LOCAL_ONLY)) { memcpy(ConferenceIDSource.ConferenceID.buffer, &id, min(sizeof(ConferenceIDSource.ConferenceID.buffer), sizeof(UUID))); } else ASSERT(0); memcpy(pConferenceID->buffer, ConferenceIDSource.ConferenceID.buffer, sizeof(pConferenceID->buffer));
LeaveCriticalSection(&(ConferenceIDSource.Lock)); return; }
//====================================================================================
// This function is used internally whenever a function needs to send a PDU.
// Note that before a datalinkSendRequest() is done, the call object is unlocked
// and then subsequently locked after returning. This is necessary to prevent deadlock
// in MT apps. Further, it is the responsibility of calling functions to revalidate
// the call object before using it.
//====================================================================================
CS_STATUS Q931SendMessage( P_CALL_OBJECT pCallObject, BYTE* CodedPtrPDU, DWORD CodedLengthPDU, BOOL bOkToUnlock) { HQ931CALL hQ931Call; DWORD dwPhysicalId; HRESULT result;
ASSERT(pCallObject != NULL); ASSERT(CodedPtrPDU != NULL); ASSERT(CodedLengthPDU != 0);
hQ931Call = pCallObject->hQ931Call; dwPhysicalId = pCallObject->dwPhysicalId;
// send the message.
if (pCallObject->bConnected) { // Unlock the call object before we call down to Link Layer (if caller said it was ok)
if(bOkToUnlock) CallObjectUnlock(pCallObject);
#if (defined(_DEBUG) && defined(PCS_COMPLIANCE))
InteropOutput(Q931Logger, (BYTE FAR*)CodedPtrPDU, CodedLengthPDU, Q931LOG_SENT_PDU); #endif
result = datalinkSendRequest(dwPhysicalId, CodedPtrPDU, CodedLengthPDU);
// Now attempt to lock the object again. Note: higher level funcs must
// be sure to call CallObjectValidate before assuming they have a valid lock
if (bOkToUnlock && ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL))) { Q931DBG((DBGERROR, "CallObjectLock() returned error (object not found).")); }
// Note: if we can't get the lock, perhaps we should pass back a specific return code
// that higher layers can check for??? For now, they should call CallObjectValidate()
// before assuming the call object is still good.
if (FAILED(result)) { Q931DBG((DBGERROR, "datalinkSendRequest() failed")); Free(CodedPtrPDU); } return result; }
Q931DBG((DBGWARNING, "Q931SendMessage: message not sent because bConnected is FALSE")); Free(CodedPtrPDU); return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931RingingInternal(P_CALL_OBJECT pCallObject, WORD wCRV) { CC_ENDPOINTTYPE EndpointType; DWORD CodedLengthASN; BYTE *CodedPtrASN; BINARY_STRING UserUserData; DWORD CodedLengthPDU; BYTE *CodedPtrPDU; HRESULT result = CS_OK; int nError = 0; HQ931CALL hQ931Call = pCallObject->hQ931Call;
if (pCallObject->VendorInfoPresent) EndpointType.pVendorInfo = &pCallObject->VendorInfo; else EndpointType.pVendorInfo = NULL; EndpointType.bIsTerminal = pCallObject->bIsTerminal; EndpointType.bIsGateway = pCallObject->bIsGateway;
result = Q931AlertingEncodeASN( NULL, /* pNonStandardData */ NULL, /* h245Addr */ &EndpointType, &pCallObject->World, &CodedPtrASN, &CodedLengthASN);
if (result != CS_OK || CodedLengthASN == 0 || CodedPtrASN == NULL) { Q931DBG((DBGERROR, "Q931AlertingEncodeASN() failed, nothing to send.")); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } return (result != CS_OK) ? result : CS_INTERNAL_ERROR; }
UserUserData.length = (WORD)CodedLengthASN; UserUserData.ptr = CodedPtrASN;
result = Q931AlertingEncodePDU(wCRV, &UserUserData, &CodedPtrPDU, &CodedLengthPDU);
if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); }
if ((result != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { Q931DBG((DBGERROR, "Q931AlertingEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } if (result != CS_OK) { return result; } return CS_INTERNAL_ERROR; } else { result = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, TRUE); if(CallObjectValidate(hQ931Call) != CS_OK) return(CS_INTERNAL_ERROR);
} return result; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallSetup( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, Q931_SETUP_ASN *pSetupASN) { DWORD result; HQ931CALL hQ931Call; HRESULT Status;
// if the callstate is anything other than null, ignore...
// if (pCallObject->bCallState != CALLSTATE_NULL)
// {
// return CS_OK;
// }
hQ931Call = pCallObject->hQ931Call;
if (pMessage->CallReference & 0x8000) { // the message came from the callee, so this should be ignored???
} pMessage->CallReference &= ~(0x8000); // strip off the high bit.
pCallObject->wCRV = pMessage->CallReference;
pCallObject->wGoal = pSetupASN->wGoal; pCallObject->bCallerIsMC = pSetupASN->bCallerIsMC; pCallObject->wCallType = pSetupASN->wCallType; pCallObject->ConferenceID = pSetupASN->ConferenceID;
pCallObject->bCallState = CALLSTATE_PRESENT;
{ CSS_CALL_INCOMING EventData; WCHAR szUnicodeDisplay[CC_MAX_DISPLAY_LENGTH + 1]; WCHAR szUnicodeCalledPartyNumber[CC_MAX_PARTY_NUMBER_LEN + 1]; WCHAR szUnicodeCallingPartyNumber[CC_MAX_PARTY_NUMBER_LEN + 1];
EventData.wGoal = pCallObject->wGoal; EventData.wCallType = pCallObject->wCallType; EventData.bCallerIsMC = pCallObject->bCallerIsMC; EventData.ConferenceID = pCallObject->ConferenceID;
EventData.pSourceAddr = NULL; if (pSetupASN->SourceAddrPresent) { EventData.pSourceAddr = &(pSetupASN->SourceAddr); }
EventData.pCallerAddr = NULL; if (pSetupASN->CallerAddrPresent) { EventData.pCallerAddr = &(pSetupASN->CallerAddr); }
EventData.pCalleeDestAddr = NULL; if (pSetupASN->CalleeDestAddrPresent) { EventData.pCalleeDestAddr = &(pSetupASN->CalleeDestAddr); }
EventData.pLocalAddr = NULL; if (pSetupASN->CalleeAddrPresent) { EventData.pLocalAddr = &(pSetupASN->CalleeAddr); }
if (!(pSetupASN->NonStandardDataPresent) || (pSetupASN->NonStandardData.sData.wOctetStringLength == 0) || (pSetupASN->NonStandardData.sData.pOctetString == NULL)) { EventData.pNonStandardData = NULL; } else { EventData.pNonStandardData = &(pSetupASN->NonStandardData); }
EventData.pCallerAliasList = pSetupASN->pCallerAliasList; EventData.pCalleeAliasList = pSetupASN->pCalleeAliasList; EventData.pExtraAliasList = pSetupASN->pExtraAliasList; EventData.pExtensionAliasItem = pSetupASN->pExtensionAliasItem;
EventData.pszDisplay = NULL; if (pMessage->Display.Present && pMessage->Display.Contents) { MultiByteToWideChar(CP_ACP, 0, (const char *)pMessage->Display.Contents, -1, szUnicodeDisplay, sizeof(szUnicodeDisplay) / sizeof(szUnicodeDisplay[0])); EventData.pszDisplay = szUnicodeDisplay; }
EventData.pszCalledPartyNumber = NULL; if (pMessage->CalledPartyNumber.Present && pMessage->CalledPartyNumber.PartyNumberLength) {
MultiByteToWideChar(CP_ACP, 0, (const char *)pMessage->CalledPartyNumber.PartyNumbers, -1, szUnicodeCalledPartyNumber, sizeof(szUnicodeCalledPartyNumber) / sizeof(szUnicodeCalledPartyNumber[0])); EventData.pszCalledPartyNumber = szUnicodeCalledPartyNumber; }
//nikhilb:change for CPR
if (pMessage->CallingPartyNumber.Present && (pMessage->CallingPartyNumber.Length > 1) ) { if( (EventData.pCallerAliasList == NULL) || (EventData.pCallerAliasList->wCount == 0) || (EventData.pCallerAliasList->pItems == NULL) ) { // Always skip 1st byte in the contents.
// Skip the 2nd byte if its not an e.164 char (could be the screening indicator byte)
BYTE* pstrTemp = pMessage->CallingPartyNumber.Contents + ((pMessage->CallingPartyNumber.Contents[1] & 0x80)? 2 : 1);
MultiByteToWideChar(CP_ACP, 0, (const char *)(pstrTemp), -1, szUnicodeCallingPartyNumber, sizeof(szUnicodeCallingPartyNumber) / sizeof(szUnicodeCallingPartyNumber[0])); if( EventData.pCallerAliasList == NULL ) { EventData.pCallerAliasList = (PCC_ALIASNAMES)malloc( sizeof(CC_ALIASNAMES) ); } if( EventData.pCallerAliasList != NULL ) { EventData.pCallerAliasList->wCount = 1; EventData.pCallerAliasList->pItems = (PCC_ALIASITEM)malloc( sizeof(CC_ALIASITEM) ); if( EventData.pCallerAliasList->pItems == NULL ) { free( EventData.pCallerAliasList ); EventData.pCallerAliasList = NULL; } else { ZeroMemory( EventData.pCallerAliasList->pItems, sizeof(CC_ALIASITEM) ); EventData.pCallerAliasList->pItems[0].wType = CC_ALIAS_H323_PHONE; EventData.pCallerAliasList->pItems[0].wDataLength = (WORD)wcslen( szUnicodeCallingPartyNumber ); EventData.pCallerAliasList->pItems[0].pData = (WCHAR*) malloc( (EventData.pCallerAliasList->pItems[0].wDataLength+1) * sizeof(WCHAR) ); if( EventData.pCallerAliasList->pItems[0].pData == NULL ) { free( EventData.pCallerAliasList->pItems ); free( EventData.pCallerAliasList ); EventData.pCallerAliasList = NULL; } else { CopyMemory( EventData.pCallerAliasList->pItems[0].pData, szUnicodeCallingPartyNumber, (EventData.pCallerAliasList->pItems[0].wDataLength+1) * sizeof(WCHAR) ); } } } } }
//nikhilb:change for CPR
if (pMessage->CalledPartyNumber.Present && (pMessage->CalledPartyNumber.PartyNumberLength > 0) ) { if( (EventData.pCalleeAliasList == NULL) || (EventData.pCalleeAliasList->wCount == 0) || (EventData.pCalleeAliasList->pItems == NULL) ) { MultiByteToWideChar(CP_ACP, 0, (const char *)(pMessage->CalledPartyNumber.PartyNumbers), -1, szUnicodeCalledPartyNumber, sizeof(szUnicodeCalledPartyNumber) / sizeof(szUnicodeCalledPartyNumber[0])); if( EventData.pCalleeAliasList == NULL ) { EventData.pCalleeAliasList = (PCC_ALIASNAMES)malloc( sizeof(CC_ALIASNAMES) ); } if( EventData.pCalleeAliasList != NULL ) { EventData.pCalleeAliasList->wCount = 1; EventData.pCalleeAliasList->pItems = (PCC_ALIASITEM)malloc( sizeof(CC_ALIASITEM) ); if( EventData.pCalleeAliasList->pItems == NULL ) { free( EventData.pCalleeAliasList ); EventData.pCalleeAliasList = NULL; } else { ZeroMemory( EventData.pCalleeAliasList->pItems, sizeof(CC_ALIASITEM) ); EventData.pCalleeAliasList->pItems[0].wType = CC_ALIAS_H323_PHONE; EventData.pCalleeAliasList->pItems[0].wDataLength = (WORD)wcslen( szUnicodeCalledPartyNumber ); EventData.pCalleeAliasList->pItems[0].pData = (WCHAR*) malloc( (EventData.pCalleeAliasList->pItems[0].wDataLength+1) * sizeof(WCHAR) ); if( EventData.pCalleeAliasList->pItems[0].pData == NULL ) { free( EventData.pCalleeAliasList->pItems ); free( EventData.pCalleeAliasList ); EventData.pCalleeAliasList = NULL; } else { CopyMemory( EventData.pCalleeAliasList->pItems[0].pData, szUnicodeCalledPartyNumber, (EventData.pCalleeAliasList->pItems[0].wDataLength+1) * sizeof(WCHAR) ); } } } } }
EventData.pSourceEndpointType = &(pSetupASN->EndpointType);
EventData.wCallReference = pMessage->CallReference;
result = pCallObject->Callback((BYTE)Q931_CALL_INCOMING, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData);
}
Status = CallObjectValidate(hQ931Call); if (Status != CS_OK) return Status;
if (result == 0) { WORD wCRV = (WORD)(pMessage->CallReference | 0x8000); HRESULT Status;
Status = Q931RingingInternal(pCallObject, wCRV); if (Status != CS_OK) { return Status; } pCallObject->bCallState = CALLSTATE_RECEIVED; } return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931Ringing( HQ931CALL hQ931Call, WORD *pwCRV) { P_CALL_OBJECT pCallObject = NULL; CS_STATUS Status; WORD wCRV;
if (bQ931Initialized == FALSE) { ASSERT(FALSE); return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Entering Q931Ringing()..."));
// need parameter checking...
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error (object not found).")); return CS_BAD_PARAM; }
if (pwCRV != NULL) { wCRV = *pwCRV; } else { wCRV = pCallObject->wCRV; }
Status = Q931RingingInternal(pCallObject, wCRV); if (Status != CS_OK) { return Status; }
pCallObject->bCallState = CALLSTATE_RECEIVED; Status = CallObjectUnlock(pCallObject);
return Status; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallProceeding( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, Q931_CALL_PROCEEDING_ASN *pProceedingASN) { pCallObject->bCallState = CALLSTATE_OUTGOING;
Q931StopTimer(pCallObject, Q931_TIMER_303);
return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallAlerting( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, Q931_ALERTING_ASN *pAlertingASN) { DWORD result;
pCallObject->bCallState = CALLSTATE_DELIVERED;
if (pAlertingASN != NULL) { // we could pass h245addr, userinfo, and conferenceid
// if desired later...
// (this would be passed in the pAlertingASN field)
}
Q931StopTimer(pCallObject, Q931_TIMER_303); Q931StartTimer(pCallObject, Q931_TIMER_301);
result = pCallObject->Callback((BYTE)Q931_CALL_RINGING, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, NULL);
return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallConnect( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, Q931_CONNECT_ASN *pConnectASN) { DWORD result;
if ((pMessage->CallReference & 0x8000) == 0) { // the message came from the caller, so this should be ignored???
} pMessage->CallReference &= ~(0x8000); // strip off the high bit.
pCallObject->ConferenceID = pConnectASN->ConferenceID;
pCallObject->bCallState = CALLSTATE_ACTIVE;
{ CSS_CALL_ACCEPTED EventData; WCHAR szUnicodeDisplay[CC_MAX_DISPLAY_LENGTH + 1];
// populate the event data struct.
EventData.ConferenceID = pCallObject->ConferenceID;
if (pCallObject->PeerCallAddrPresent) { EventData.pCalleeAddr = &(pCallObject->PeerCallAddr); } else { EventData.pCalleeAddr = NULL; } EventData.pLocalAddr = &(pCallObject->LocalAddr);
EventData.pH245Addr = NULL; if (pConnectASN->h245AddrPresent) { EventData.pH245Addr = &(pConnectASN->h245Addr); }
if (!(pConnectASN->NonStandardDataPresent) || (pConnectASN->NonStandardData.sData.wOctetStringLength == 0) || (pConnectASN->NonStandardData.sData.pOctetString == NULL)) { EventData.pNonStandardData = NULL; } else { EventData.pNonStandardData = &(pConnectASN->NonStandardData); }
EventData.pszDisplay = NULL; if (pMessage->Display.Present && pMessage->Display.Contents) { MultiByteToWideChar(CP_ACP, 0, (const char *)pMessage->Display.Contents, -1, szUnicodeDisplay, sizeof(szUnicodeDisplay) / sizeof(szUnicodeDisplay[0])); EventData.pszDisplay = szUnicodeDisplay; }
EventData.pDestinationEndpointType = &(pConnectASN->EndpointType);
EventData.wCallReference = pMessage->CallReference;
Q931StopTimer(pCallObject, Q931_TIMER_303); Q931StopTimer(pCallObject, Q931_TIMER_301);
result = pCallObject->Callback((BYTE)Q931_CALL_ACCEPTED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); }
return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallReleaseComplete( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, Q931_RELEASE_COMPLETE_ASN *pReleaseCompleteASN) { DWORD result; BYTE bCause = 0;
if (pMessage && pMessage->Cause.Present && (pMessage->Cause.Length >= 3)) { bCause = (BYTE)(pMessage->Cause.Contents[2] & (~CAUSE_EXT_BIT)); }
Q931StopTimer(pCallObject, Q931_TIMER_303); Q931StopTimer(pCallObject, Q931_TIMER_301);
// if this is the callee, or the call has been connected already,
// then this message should be treated as hangup (not reject).
if (!(pCallObject->fIsCaller) || (pCallObject->bCallState == CALLSTATE_ACTIVE) || (bCause == CAUSE_VALUE_NORMAL_CLEAR)) { CSS_CALL_REMOTE_HANGUP EventData;
EventData.bReason = CC_REJECT_NORMAL_CALL_CLEARING; pCallObject->bCallState = CALLSTATE_NULL;
result = pCallObject->Callback((BYTE)Q931_CALL_REMOTE_HANGUP, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); } else { CSS_CALL_REJECTED EventData;
pCallObject->bCallState = CALLSTATE_NULL;
// populate the event data struct.
switch (bCause) { case CAUSE_VALUE_NORMAL_CLEAR: EventData.bRejectReason = CC_REJECT_NORMAL_CALL_CLEARING; break; case CAUSE_VALUE_USER_BUSY: EventData.bRejectReason = CC_REJECT_USER_BUSY; break; case CAUSE_VALUE_NO_ANSWER: EventData.bRejectReason = CC_REJECT_NO_ANSWER; break; case CAUSE_VALUE_NOT_IMPLEMENTED: EventData.bRejectReason = CC_REJECT_NOT_IMPLEMENTED; break; case CAUSE_VALUE_INVALID_CRV: EventData.bRejectReason = CC_REJECT_INVALID_IE_CONTENTS; break; case CAUSE_VALUE_IE_MISSING: EventData.bRejectReason = CC_REJECT_MANDATORY_IE_MISSING; break; case CAUSE_VALUE_IE_CONTENTS: EventData.bRejectReason = CC_REJECT_INVALID_IE_CONTENTS; break; case CAUSE_VALUE_TIMER_EXPIRED: EventData.bRejectReason = CC_REJECT_TIMER_EXPIRED; break; default: EventData.bRejectReason = pReleaseCompleteASN->bReason; break; }
EventData.ConferenceID = pCallObject->ConferenceID;
EventData.pAlternateAddr = NULL;
if (!(pReleaseCompleteASN->NonStandardDataPresent) || (pReleaseCompleteASN->NonStandardData.sData.wOctetStringLength == 0) || (pReleaseCompleteASN->NonStandardData.sData.pOctetString == NULL)) { EventData.pNonStandardData = NULL; } else { EventData.pNonStandardData = &(pReleaseCompleteASN->NonStandardData); }
result = pCallObject->Callback((BYTE)Q931_CALL_REJECTED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); }
return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallFacility( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, Q931_FACILITY_ASN *pFacilityASN) { DWORD result;
// if this is the callee, or the call has been connected already,
// then this message should be treated as hangup (not reject).
if (!(pCallObject->fIsCaller) || (pCallObject->bCallState == CALLSTATE_ACTIVE)) { CSS_CALL_REMOTE_HANGUP EventData;
EventData.bReason = pFacilityASN->bReason; pCallObject->bCallState = CALLSTATE_NULL;
result = pCallObject->Callback((BYTE)Q931_CALL_REMOTE_HANGUP, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); } else { CSS_CALL_REJECTED EventData;
pCallObject->bCallState = CALLSTATE_NULL;
// populate the event data struct.
EventData.bRejectReason = pFacilityASN->bReason;
EventData.ConferenceID = pFacilityASN->ConferenceIDPresent ? pFacilityASN->ConferenceID : pCallObject->ConferenceID;
EventData.pAlternateAddr = &(pFacilityASN->AlternativeAddr);
if (!(pFacilityASN->NonStandardDataPresent) || (pFacilityASN->NonStandardData.sData.wOctetStringLength == 0) || (pFacilityASN->NonStandardData.sData.pOctetString == NULL)) { EventData.pNonStandardData = NULL; } else { EventData.pNonStandardData = &(pFacilityASN->NonStandardData); }
result = pCallObject->Callback((BYTE)Q931_CALL_REJECTED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); }
return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931SendReleaseCompleteMessage( P_CALL_OBJECT pCallObject, BYTE bRejectReason, PCC_CONFERENCEID pConferenceID, PCC_ADDR pAlternateAddr, PCC_NONSTANDARDDATA pNonStandardData) { CS_STATUS result = CS_OK; HQ931CALL hQ931Call = pCallObject->hQ931Call;
// since this call is going away, mark the call object for deletion so any other
// threads attempting to use this object will fail to get a lock on it.
CallObjectMarkForDelete(hQ931Call);
if((bRejectReason == CC_REJECT_ROUTE_TO_GATEKEEPER) || (bRejectReason == CC_REJECT_CALL_FORWARDED) || (bRejectReason == CC_REJECT_ROUTE_TO_MC)) { // send the FACILITY message to the peer to reject the call.
DWORD CodedLengthASN; BYTE *CodedPtrASN; HRESULT ResultASN = CS_OK; CC_ADDR AltAddr;
MakeBinaryADDR(pAlternateAddr, &AltAddr);
ResultASN = Q931FacilityEncodeASN(pNonStandardData, (pAlternateAddr ? &AltAddr : NULL), bRejectReason, pConferenceID, NULL, &pCallObject->World, &CodedPtrASN, &CodedLengthASN); if ((ResultASN != CS_OK) || (CodedLengthASN == 0) || (CodedPtrASN == NULL)) { Q931DBG((DBGERROR, "Q931FacilityEncodeASN() failed, nothing to send.")); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } result = CS_INTERNAL_ERROR; } else { DWORD CodedLengthPDU; BYTE *CodedPtrPDU; BINARY_STRING UserUserData; HRESULT ResultEncode = CS_OK; WORD wCRV; if (pCallObject->fIsCaller) { wCRV = (WORD)(pCallObject->wCRV & 0x7FFF); } else { wCRV = (WORD)(pCallObject->wCRV | 0x8000); }
UserUserData.length = (WORD)CodedLengthASN; UserUserData.ptr = CodedPtrASN;
ResultEncode = Q931FacilityEncodePDU(wCRV, &UserUserData, &CodedPtrPDU, &CodedLengthPDU); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } if ((ResultEncode != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { Q931DBG((DBGERROR, "Q931FacilityEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } result = CS_INTERNAL_ERROR; } else { result = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, FALSE); } } } else { // send the RELEASE COMPLETE message to the peer to reject call.
DWORD CodedLengthASN; BYTE *CodedPtrASN; HRESULT ResultASN = CS_OK; BYTE bReasonUU = bRejectReason; BYTE *pbReasonUU = &bReasonUU;
switch (bReasonUU) { case CC_REJECT_NO_BANDWIDTH: case CC_REJECT_GATEKEEPER_RESOURCES: case CC_REJECT_UNREACHABLE_DESTINATION: case CC_REJECT_DESTINATION_REJECTION: case CC_REJECT_INVALID_REVISION: case CC_REJECT_NO_PERMISSION: case CC_REJECT_UNREACHABLE_GATEKEEPER: case CC_REJECT_GATEWAY_RESOURCES: case CC_REJECT_BAD_FORMAT_ADDRESS: case CC_REJECT_ADAPTIVE_BUSY: case CC_REJECT_IN_CONF: case CC_REJECT_CALL_DEFLECTION: case CC_REJECT_USER_BUSY: break; default: pbReasonUU = NULL; break; }
ResultASN = Q931ReleaseCompleteEncodeASN(pNonStandardData, pConferenceID, pbReasonUU, &pCallObject->World, &CodedPtrASN, &CodedLengthASN); if ((ResultASN != CS_OK) || (CodedLengthASN == 0) || (CodedPtrASN == NULL)) { Q931DBG((DBGERROR, "Q931ReleaseCompleteEncodeASN() failed, nothing to send.")); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } result = CS_INTERNAL_ERROR; } else { DWORD CodedLengthPDU; BYTE *CodedPtrPDU; BINARY_STRING UserUserData; HRESULT ResultEncode = CS_OK; BYTE bCause = 0; BYTE *pbCause = &bCause; WORD wCRV;
if (pCallObject->fIsCaller) { wCRV = (WORD)(pCallObject->wCRV & 0x7FFF); } else { wCRV = (WORD)(pCallObject->wCRV | 0x8000); }
UserUserData.length = (WORD)CodedLengthASN; UserUserData.ptr = CodedPtrASN;
switch (bRejectReason) { case CC_REJECT_NORMAL_CALL_CLEARING: bCause = CAUSE_VALUE_NORMAL_CLEAR; break; case CC_REJECT_USER_BUSY: bCause = CAUSE_VALUE_USER_BUSY; break; case CC_REJECT_NO_ANSWER: bCause = CAUSE_VALUE_NO_ANSWER; break; case CC_REJECT_NOT_IMPLEMENTED: bCause = CAUSE_VALUE_NOT_IMPLEMENTED; break; case CC_REJECT_MANDATORY_IE_MISSING: bCause = CAUSE_VALUE_IE_MISSING; break; case CC_REJECT_INVALID_IE_CONTENTS: bCause = CAUSE_VALUE_IE_CONTENTS; break; case CC_REJECT_TIMER_EXPIRED: bCause = CAUSE_VALUE_TIMER_EXPIRED; break; default: pbCause = NULL; break; }
ResultEncode = Q931ReleaseCompleteEncodePDU(wCRV, pbCause, &UserUserData, &CodedPtrPDU, &CodedLengthPDU); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } if ((ResultEncode != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { Q931DBG((DBGERROR, "Q931ReleaseCompleteEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } result = CS_INTERNAL_ERROR; } else { result = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, FALSE); } } }
pCallObject->bCallState = CALLSTATE_NULL;
if (result != CS_OK) { return result; } return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931SendStatusMessage( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage, BYTE bCause) { CS_STATUS result = CS_OK;
DWORD CodedLengthPDU; BYTE *CodedPtrPDU; HRESULT EncodePDU = CS_OK; int nError = 0; HQ931CALL hQ931Call = pCallObject->hQ931Call; WORD wCRV; if (pCallObject->fIsCaller) { wCRV = (WORD)(pCallObject->wCRV & 0x7FFF); } else { wCRV = (WORD)(pCallObject->wCRV | 0x8000); }
EncodePDU = Q931StatusEncodePDU(wCRV, NULL, bCause, pCallObject->bCallState, &CodedPtrPDU, &CodedLengthPDU); if ((EncodePDU != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { Q931DBG((DBGERROR, "Q931StatusEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } result = CS_INTERNAL_ERROR; } else { result = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, TRUE); if(CallObjectValidate(hQ931Call) != CS_OK) return(CS_INTERNAL_ERROR); } return(result); }
//====================================================================================
//====================================================================================
CS_STATUS Q931SendProceedingMessage( HQ931CALL hQ931Call, WORD wCallReference, PCC_ENDPOINTTYPE pDestinationEndpointType, PCC_NONSTANDARDDATA pNonStandardData) { CS_STATUS result = CS_OK;
DWORD CodedLengthASN; BYTE *CodedPtrASN; HRESULT ResultASN = CS_OK; DWORD dwPhysicalId = INVALID_PHYS_ID; P_CALL_OBJECT pCallObject = NULL;
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error")); return CS_SUBSYSTEM_FAILURE; } dwPhysicalId = pCallObject->dwPhysicalId;
// first build the ASN portion of the message (user to user part)
ResultASN = Q931ProceedingEncodeASN( pNonStandardData, NULL, // No H245 address.
pDestinationEndpointType, // EndpointType information.
&pCallObject->World, &CodedPtrASN, &CodedLengthASN);
if ((ResultASN != CS_OK) || (CodedLengthASN == 0) || (CodedPtrASN == NULL)) { Q931DBG((DBGERROR, "Q931ProceedingEncodeASN() failed, nothing to send."));
if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } result = CS_INTERNAL_ERROR; } else { // now build the rest of the message
DWORD CodedLengthPDU; BYTE *CodedPtrPDU; BINARY_STRING UserUserData; HRESULT ResultEncode = CS_OK; WORD wCRV = (WORD)(wCallReference | 0x8000);
UserUserData.length = (WORD)CodedLengthASN; UserUserData.ptr = CodedPtrASN;
ResultEncode = Q931ProceedingEncodePDU(wCRV, &UserUserData, &CodedPtrPDU, &CodedLengthPDU); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } if ((ResultEncode != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { Q931DBG((DBGERROR, "Q931ProceedingEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } result = CS_INTERNAL_ERROR; } else { result = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, TRUE);
if (CallObjectValidate(hQ931Call) != CS_OK) return(CS_INTERNAL_ERROR); } } CallObjectUnlock(pCallObject); return(result); }
//====================================================================================
//====================================================================================
CS_STATUS Q931SendPDU(HQ931CALL hQ931Call, BYTE* CodedPtrPDU, DWORD CodedLengthPDU) { CS_STATUS result = CS_OK; HRESULT TempResult; P_CALL_OBJECT pCallObject = NULL;
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error")); return CS_SUBSYSTEM_FAILURE; }
TempResult = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, TRUE);
if (CallObjectValidate(hQ931Call) != CS_OK) return(CS_INTERNAL_ERROR);
if(FAILED(TempResult)) { CSS_CALL_FAILED EventData; EventData.error = TempResult; if ((pCallObject->bCallState == CALLSTATE_ACTIVE) && (pCallObject->bResolved)) { pCallObject->Callback(Q931_CALL_CONNECTION_CLOSED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, NULL); } else { pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); }
if (CallObjectValidate(hQ931Call) == CS_OK) { DWORD dwId = pCallObject->dwPhysicalId; if ((pCallObject->bCallState != CALLSTATE_ACTIVE) || (!pCallObject->bResolved)) { CallObjectDestroy(pCallObject); pCallObject = NULL; } linkLayerShutdown(dwId); if (pCallObject) { pCallObject->bConnected = FALSE; } } return TempResult; } CallObjectUnlock(pCallObject); return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931OnCallStatusEnquiry( P_CALL_OBJECT pCallObject, Q931MESSAGE *pMessage) { CS_STATUS SendStatus;
SendStatus = Q931SendStatusMessage(pCallObject, pMessage, CAUSE_VALUE_ENQUIRY_RESPONSE);
return SendStatus; }
//====================================================================================
//====================================================================================
void Q931SendComplete(DWORD instance, HRESULT msg, PBYTE buf, DWORD length) { HQ931CALL hQ931Call = (HQ931CALL)instance; P_CALL_OBJECT pCallObject = NULL;
Q931DBG((DBGTRACE, "Entering Q931SendComplete()..."));
if (buf != NULL) { Free(buf); }
if (FAILED(msg)) { // shut down link layer; report failure to client
CSS_CALL_FAILED EventData;
Q931DBG((DBGERROR, "error in datalinkSendRequest()"));
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error")); return; }
EventData.error = msg; if ((pCallObject->bCallState == CALLSTATE_ACTIVE) && (pCallObject->bResolved)) { pCallObject->Callback(Q931_CALL_CONNECTION_CLOSED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, NULL); } else { pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); }
if (CallObjectValidate(hQ931Call) == CS_OK) { DWORD dwId = pCallObject->dwPhysicalId; if ((pCallObject->bCallState != CALLSTATE_ACTIVE) || (!pCallObject->bResolved)) { CallObjectDestroy(pCallObject); pCallObject = NULL; } linkLayerShutdown(dwId); if (pCallObject) { pCallObject->bConnected = FALSE; } } return; } return; }
//====================================================================================
//====================================================================================
static DWORD PostReceiveBuffer(DWORD dwPhysicalId, BYTE *buf) { if (buf == NULL) { buf = Malloc(RECEIVE_BUFFER_SIZE); } return datalinkReceiveRequest(dwPhysicalId, buf, RECEIVE_BUFFER_SIZE); }
//====================================================================================
//====================================================================================
void OnReceiveCallback(DWORD instance, HRESULT message, Q931MESSAGE *pMessage, BYTE *buf, DWORD nbytes) { HQ931CALL hQ931Call = (HQ931CALL)instance; P_CALL_OBJECT pCallObject = NULL; DWORD dwPhysicalId; Q931DBG((DBGTRACE, "Entering ReceiveCallback()..."));
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { if (buf) { Free(buf); } Q931DBG((DBGTRACE, "Call Object no longer available: 0x%08lx", hQ931Call)); return; }
if (message == LINK_RECV_DATA) { HRESULT Result = CS_OK;
if ((buf == NULL) || (nbytes == 0)) { Q931DBG((DBGERROR, "Empty buffer received as data.")); CallObjectUnlock(pCallObject); return; }
// This block is the Q931 call re-connect implementation:
// if the object related to the incoming message is not yet resolved...
if (pCallObject->bResolved == FALSE) { // try to resolve the object.
HQ931CALL hFoundCallObject; P_CALL_OBJECT pFoundCallObject = NULL;
// If found another object with matching CRV/Addr...
if (CallObjectFind(&hFoundCallObject, pCallObject->wCRV, &(pCallObject->PeerConnectAddr)) && ((CallObjectLock(hFoundCallObject, &pFoundCallObject) == CS_OK) && (pFoundCallObject != NULL))) { // friendly channel close of the pFoundCallObject.
Q931SendReleaseCompleteMessage(pFoundCallObject, CC_REJECT_UNDEFINED_REASON, &(pFoundCallObject->ConferenceID), NULL, NULL);
// unlock the call object before calling shutdown
CallObjectUnlock(pFoundCallObject); linkLayerShutdown(pFoundCallObject->dwPhysicalId);
if((CallObjectLock(hFoundCallObject, &pFoundCallObject) != CS_OK) || (pFoundCallObject == NULL)) return;
// assign the new dwPhysicalId to found object.
pFoundCallObject->dwPhysicalId = pCallObject->dwPhysicalId;
// new object should be destroyed.
CallObjectDestroy(pCallObject); pCallObject = pFoundCallObject; } else { // The call is a newly established call, so resolve it now.
pCallObject->bResolved = TRUE; } }
Result = Q931ParseMessage((BYTE *)buf, nbytes, pMessage);
#if (defined(_DEBUG) && defined(PCS_COMPLIANCE))
InteropOutput(Q931Logger, buf, nbytes, Q931LOG_RECEIVED_PDU); #endif
// A message is to be ignored (per 5.8.1 and 5.8.2) if:
// - protocol discriminator is not recognized
// - message is too short to contain a complete message
// type information element
if ( Result != CS_OK && Result != CS_MESSAGE_TOO_SHORT && Result != CS_INVALID_PROTOCOL) { Result = Q931SendStatusMessage(pCallObject, pMessage, CAUSE_VALUE_INVALID_MSG);
Q931DBG((DBGERROR, "Q931ParseMessage(): failed."));
if(CallObjectValidate(hQ931Call) != CS_OK) { if (buf) { Free(buf); } return; }
dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); return; }
if (pMessage->Shift.Present) { Q931DBG((DBGERROR, "Shift present in message: dropped.")); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); return; }
// If a hooking procedure has been installed,
// give it first shot at acting on the received PDU.
// If it returns TRUE, then processing is finished.
if (gReceivePDUHookProc) { BOOL bHookProcessedMessage; bHookProcessedMessage = gReceivePDUHookProc(pMessage, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken); if (bHookProcessedMessage) { if (CallObjectValidate(hQ931Call) == CS_OK) { dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); } return; } }
// Message now contains the values of the Q931 PDU elements...
switch (pMessage->MessageType) { case SETUPMESSAGETYPE: { Q931_SETUP_ASN SetupASN;
if (!pMessage->UserToUser.Present || (pMessage->UserToUser.UserInformationLength == 0)) { Q931DBG((DBGERROR, "ReceiveCallback(): Message is missing ASN.1 UserUser data...")); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); return; }
Q931DBG((DBGTRACE, "ReceiveCallback(): received Setup message...")); Result = Q931SetupParseASN(&pCallObject->World, pMessage->UserToUser.UserInformation, pMessage->UserToUser.UserInformationLength, &SetupASN); if (Result == CS_OPTION_NOT_IMPLEMENTED) { //... maybe callback callcont in later drop.
// initiate a disconnect sequence from the caller side.
if (Q931SendReleaseCompleteMessage(pCallObject, CC_REJECT_TIMER_EXPIRED, NULL, NULL, NULL) != CS_OK) { // nothing to do if this fails.
}
dwPhysicalId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwPhysicalId); if (buf) { Free(buf); buf = NULL; } return; } if (Result != CS_OK) { Q931DBG((DBGERROR, "ReceiveCallback(): Unable to parse ASN.1 data.")); break; }
// The "CallerAddr is not passed in the PDU, so the
// only valuable addr to use is the connection addr
// passed from the link layer and saved into the call
// object at connect-time.
SetupASN.CallerAddrPresent = TRUE; SetupASN.CallerAddr = pCallObject->PeerConnectAddr;
// The "CalleeAddr" which is passed in the PDU is ignored
// by the ASN parser, and supplied by the link layer
// instead and saved into the call object at connect-time.
// here, this address is used as the callee addr.
SetupASN.CalleeAddrPresent = TRUE; SetupASN.CalleeAddr = pCallObject->LocalAddr;
Result = Q931OnCallSetup(pCallObject, pMessage, &SetupASN);
_FreeSetupASN(&SetupASN); } break; case RELEASECOMPLMESSAGETYPE: { Q931_RELEASE_COMPLETE_ASN ReleaseCompleteASN;
if (!pMessage->UserToUser.Present || (pMessage->UserToUser.UserInformationLength == 0)) { Q931DBG((DBGERROR, "ReceiveCallback(): Message is missing ASN.1 UserUser data...")); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); return; }
Q931DBG((DBGTRACE, "ReceiveCallback(): received ReleaseComplete message...")); Result = Q931ReleaseCompleteParseASN(&pCallObject->World, pMessage->UserToUser.UserInformation, pMessage->UserToUser.UserInformationLength, &ReleaseCompleteASN); if (Result != CS_OK) { Q931DBG((DBGERROR, "ReceiveCallback(): Unable to parse ASN.1 data.")); break; } Result = Q931OnCallReleaseComplete(pCallObject, pMessage, &ReleaseCompleteASN); if (CallObjectValidate(hQ931Call) == CS_OK) { dwPhysicalId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwPhysicalId); } Free(buf); _FreeReleaseCompleteASN(&ReleaseCompleteASN); return; } break; case FACILITYMESSAGETYPE: { Q931_FACILITY_ASN FacilityASN;
if (!pMessage->UserToUser.Present || (pMessage->UserToUser.UserInformationLength == 0)) { Q931DBG((DBGERROR, "ReceiveCallback(): Message is missing ASN.1 UserUser data...")); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); return; }
Q931DBG((DBGTRACE, "ReceiveCallback(): received Facility message...")); Result = Q931FacilityParseASN(&pCallObject->World, pMessage->UserToUser.UserInformation, pMessage->UserToUser.UserInformationLength, &FacilityASN); if (Result != CS_OK) { Q931DBG((DBGERROR, "ReceiveCallback(): Unable to parse ASN.1 data.")); break; }
// initiate a disconnect sequence from the caller side.
Q931SendReleaseCompleteMessage(pCallObject, CC_REJECT_CALL_DEFLECTION, NULL, NULL, NULL); Result = Q931OnCallFacility(pCallObject, pMessage, &FacilityASN); _FreeFacilityASN(&FacilityASN); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwPhysicalId); Free(buf); return; } break; case CONNECTMESSAGETYPE: { Q931_CONNECT_ASN ConnectASN;
if (!pMessage->UserToUser.Present || (pMessage->UserToUser.UserInformationLength == 0)) { Q931DBG((DBGERROR, "ReceiveCallback(): Message is missing ASN.1 UserUser data...")); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); return; }
Q931DBG((DBGTRACE, "ReceiveCallback(): received Connect message...")); Result = Q931ConnectParseASN(&pCallObject->World, pMessage->UserToUser.UserInformation, pMessage->UserToUser.UserInformationLength, &ConnectASN); if (Result != CS_OK) { Q931DBG((DBGERROR, "ReceiveCallback(): Unable to parse ASN.1 data.")); break; } Result = Q931OnCallConnect(pCallObject, pMessage, &ConnectASN); _FreeConnectASN(&ConnectASN); } break; case PROCEEDINGMESSAGETYPE: { Q931_CALL_PROCEEDING_ASN ProceedingASN;
Q931DBG((DBGTRACE, "ReceiveCallback(): received Proceeding message...")); if (!pMessage->UserToUser.Present || (pMessage->UserToUser.UserInformationLength == 0)) { Result = Q931OnCallProceeding(pCallObject, pMessage, NULL); } else { Result = Q931ProceedingParseASN(&pCallObject->World, pMessage->UserToUser.UserInformation, pMessage->UserToUser.UserInformationLength, &ProceedingASN); if (Result != CS_OK) { Q931DBG((DBGERROR, "ReceiveCallback(): Unable to parse ASN.1 data.")); break; } Result = Q931OnCallProceeding(pCallObject, pMessage, &ProceedingASN); _FreeProceedingASN(&ProceedingASN); } } break; case ALERTINGMESSAGETYPE: { Q931_ALERTING_ASN AlertingASN;
Q931DBG((DBGTRACE, "ReceiveCallback(): received Alerting message...")); if (!pMessage->UserToUser.Present || (pMessage->UserToUser.UserInformationLength == 0)) { Result = Q931OnCallAlerting(pCallObject, pMessage, NULL); } else { Result = Q931AlertingParseASN(&pCallObject->World, pMessage->UserToUser.UserInformation, pMessage->UserToUser.UserInformationLength, &AlertingASN); if (Result != CS_OK) { Q931DBG((DBGERROR, "ReceiveCallback(): Unable to parse ASN.1 data.")); break; } Result = Q931OnCallAlerting(pCallObject, pMessage, &AlertingASN); _FreeAlertingASN(&AlertingASN); } } break; case RELEASEMESSAGETYPE: case STATUSMESSAGETYPE: Q931DBG((DBGWARNING, "ReceiveCallback(): message not yet supported.")); break; case STATUSENQUIRYMESSAGETYPE: Q931DBG((DBGWARNING, "ReceiveCallback(): message not yet supported.")); Result = Q931OnCallStatusEnquiry(pCallObject, pMessage); break; default: Q931DBG((DBGERROR, "ReceiveCallback(): unknown message received.")); break; }
// re-validate the call object:
if (CallObjectValidate(hQ931Call) == CS_OK) { dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, buf); if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) return; } else { if (buf) { Free(buf); } return; }
if ( Result == CS_INCOMPATIBLE_VERSION || Result == CS_NO_MEMORY || Result == CS_SUBSYSTEM_FAILURE) { // initiate a disconnect sequence from the caller side.
Q931SendReleaseCompleteMessage(pCallObject, CC_REJECT_INVALID_REVISION, NULL, NULL, NULL); dwPhysicalId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwPhysicalId); return; }
if (Result == CS_MANDATORY_IE_MISSING) { Q931SendStatusMessage(pCallObject, pMessage, CAUSE_VALUE_IE_MISSING); } else if ( Result == CS_BAD_IE_CONTENT || Result == CS_BAD_PARAM || Result == CS_NO_FIELD_DATA) { Q931SendStatusMessage(pCallObject, pMessage, CAUSE_VALUE_IE_CONTENTS); }
} else if (message == LINK_RECV_CLOSED) { // Socket closed
if (buf) { Free(buf); } pCallObject->Callback(Q931_CALL_CONNECTION_CLOSED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, NULL);
if (CallObjectValidate(hQ931Call) == CS_OK) { dwPhysicalId = pCallObject->dwPhysicalId; pCallObject->bConnected = FALSE; CallObjectUnlock(pCallObject); linkLayerShutdown(dwPhysicalId); } return; } else if (buf) { // unknown condition?
Free(buf); }
if (CallObjectValidate(hQ931Call) == CS_OK) { CallObjectUnlock(pCallObject); }
return; }
//====================================================================================
//====================================================================================
void Q931ReceiveCallback(DWORD instance, HRESULT message, BYTE *buf, DWORD nbytes) { Q931MESSAGE *pMessage = NULL; if (message == LINK_RECV_DATA) { pMessage = (Q931MESSAGE *)Malloc(sizeof(Q931MESSAGE)); if (pMessage == NULL) { Q931DBG((DBGERROR, "Not enough memory to process Q931 message.")); // something more should be done here to indicate SERIOUS error...
return; } } OnReceiveCallback(instance, message, pMessage, buf, nbytes); if (pMessage) { Free(pMessage); } return; }
//====================================================================================
//====================================================================================
void Q931ConnectCallback(DWORD dwInstance, HRESULT dwMessage, CC_ADDR *pLocalAddr, CC_ADDR *pPeerAddr) { HQ931CALL hQ931Call = (HQ931CALL)dwInstance; P_CALL_OBJECT pCallObject = NULL; HRESULT TempResult; DWORD dwPhysicalId;
Q931DBG((DBGTRACE, "Entering Q931ConnectCallback()..."));
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error")); return; }
pCallObject->bConnected = TRUE;
if (FAILED(dwMessage)) { // shut down link layer; report failure to client
CSS_CALL_FAILED EventData;
Q931DBG((DBGERROR, "error in connect"));
EventData.error = dwMessage; pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData);
if (CallObjectValidate(hQ931Call) == CS_OK) { DWORD dwId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); } return; }
if (dwMessage != LINK_CONNECT_COMPLETE) { Q931DBG((DBGERROR, "unexpected connect callback")); CallObjectUnlock(pCallObject); return; }
if (pCallObject->bCallState == CALLSTATE_NULL) { pCallObject->bCallState = CALLSTATE_INITIATED; } pCallObject->LocalAddr = *pLocalAddr; pCallObject->PeerConnectAddr = *pPeerAddr;
// if the user specified a binary source address with address = 0,
// fill in the address with the local address and send.
if ((pCallObject->SourceAddrPresent) && (pCallObject->SourceAddr.nAddrType == CC_IP_BINARY) && (!pCallObject->SourceAddr.Addr.IP_Binary.dwAddr)) { pCallObject->SourceAddr = *pLocalAddr; }
if ((pCallObject->fIsCaller) && (pCallObject->bCallState == CALLSTATE_INITIATED)) { // send the SETUP message to the peer.
DWORD CodedLengthASN; BYTE *CodedPtrASN; HRESULT ResultASN = CS_OK;
DWORD CodedLengthPDU; BYTE *CodedPtrPDU; HRESULT ResultPDU = CS_OK;
int nError = 0; BOOL ResultSend = FALSE; BINARY_STRING UserUserData; PCC_VENDORINFO pVendorInfo = NULL; CC_NONSTANDARDDATA *pNonStandardData = NULL; DWORD dwId;
if (pCallObject->VendorInfoPresent) { pVendorInfo = &(pCallObject->VendorInfo); }
if (pCallObject->NonStandardDataPresent) { pNonStandardData = &(pCallObject->NonStandardData); }
// if there is a special callee alias list, load the calledparty#.
if (pCallObject->szCalledPartyNumber[0] == 0 && pCallObject->pCalleeAliasList != NULL && pCallObject->pCalleeAliasList->wCount == 1 && pCallObject->pCalleeAliasList->pItems[0].wType == CC_ALIAS_H323_PHONE && pCallObject->pCalleeAliasList->pItems[0].wDataLength > 0 && pCallObject->pCalleeAliasList->pItems[0].pData != NULL) { PCC_ALIASITEM pItem = &pCallObject->pCalleeAliasList->pItems[0]; WCHAR szWidePartyNumber[CC_MAX_PARTY_NUMBER_LEN + 1];
memset(szWidePartyNumber, 0 , CC_MAX_PARTY_NUMBER_LEN + 1);
if (pItem->wPrefixLength > 0 && pItem->pPrefix != NULL) { ASSERT((pItem->wPrefixLength + pItem->wDataLength +1) <= (sizeof(szWidePartyNumber)/sizeof(szWidePartyNumber[0]))); memcpy(&szWidePartyNumber[0], pItem->pPrefix, (pItem->wPrefixLength) * sizeof(WCHAR)); memcpy(&szWidePartyNumber[pItem->wPrefixLength], pItem->pData, pItem->wDataLength * sizeof(WCHAR)); } else { ASSERT((pItem->wDataLength +1) <= (sizeof(szWidePartyNumber)/sizeof(szWidePartyNumber[0]))); memcpy(szWidePartyNumber, pCallObject->pCalleeAliasList->pItems[0].pData, pItem->wDataLength * sizeof(WCHAR)); } WideCharToMultiByte(CP_ACP, 0, szWidePartyNumber, pItem->wPrefixLength + pItem->wDataLength * sizeof(WCHAR), pCallObject->szCalledPartyNumber, sizeof(pCallObject->szCalledPartyNumber), NULL, NULL); }
// may wish to pass alias parms later instead of NULL, NULL.
ResultASN = Q931SetupEncodeASN(pNonStandardData, pCallObject->SourceAddrPresent ? &(pCallObject->SourceAddr) : NULL, pCallObject->PeerCallAddrPresent ? &(pCallObject->PeerCallAddr) : NULL, // callee
pCallObject->wGoal, pCallObject->wCallType, pCallObject->bCallerIsMC, &(pCallObject->ConferenceID), pCallObject->pCallerAliasList, pCallObject->pCalleeAliasList, pCallObject->pExtraAliasList, pCallObject->pExtensionAliasItem, pVendorInfo, pCallObject->bIsTerminal, pCallObject->bIsGateway, &pCallObject->World, &CodedPtrASN, &CodedLengthASN);
if ((ResultASN != CS_OK) || (CodedLengthASN == 0) || (CodedPtrASN == NULL)) { CSS_CALL_FAILED EventData; Q931DBG((DBGERROR, "Q931SetupEncodeASN() failed, nothing to send.")); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } EventData.error = CS_INTERNAL_ERROR; dwId = pCallObject->dwPhysicalId; pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); linkLayerShutdown(dwId); if (CallObjectValidate(hQ931Call) == CS_OK) CallObjectDestroy(pCallObject); return; }
UserUserData.length = (WORD)CodedLengthASN; UserUserData.ptr = CodedPtrASN;
ResultPDU = Q931SetupEncodePDU(pCallObject->wCRV, pCallObject->szDisplay, pCallObject->szCalledPartyNumber, pCallObject->dwBandwidth, &UserUserData, &CodedPtrPDU, &CodedLengthPDU);
if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); }
if ((ResultPDU != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { CSS_CALL_FAILED EventData; Q931DBG((DBGERROR, "Q931SetupEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } EventData.error = CS_INTERNAL_ERROR; dwId = pCallObject->dwPhysicalId; pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); linkLayerShutdown(dwId); if (CallObjectValidate(hQ931Call) == CS_OK) CallObjectDestroy(pCallObject); return; }
if (pCallObject->NonStandardDataPresent) { if (pCallObject->NonStandardData.sData.pOctetString != NULL) { Free(pCallObject->NonStandardData.sData.pOctetString); pCallObject->NonStandardData.sData.pOctetString = NULL; } pCallObject->NonStandardDataPresent = FALSE; } Q931FreeAliasNames(pCallObject->pCallerAliasList); pCallObject->pCallerAliasList = NULL; Q931FreeAliasNames(pCallObject->pCalleeAliasList); pCallObject->pCalleeAliasList = NULL; Q931FreeAliasNames(pCallObject->pExtraAliasList); pCallObject->pExtraAliasList = NULL; Q931FreeAliasItem(pCallObject->pExtensionAliasItem); pCallObject->pExtensionAliasItem = NULL;
TempResult=Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, TRUE); if (CallObjectValidate(hQ931Call) != CS_OK) return;
if(FAILED(TempResult)) { CSS_CALL_FAILED EventData;
EventData.error = TempResult; dwId = pCallObject->dwPhysicalId; pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData); linkLayerShutdown(dwId); if (CallObjectValidate(hQ931Call) == CS_OK) CallObjectDestroy(pCallObject); return; }
Q931StartTimer(pCallObject, Q931_TIMER_303); } dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); PostReceiveBuffer(dwPhysicalId, NULL); }
//====================================================================================
//====================================================================================
void Q931ListenCallback(DWORD dwInstance, HRESULT dwMessage, CC_ADDR *LocalAddr, CC_ADDR *PeerAddr) { HQ931LISTEN hListenObject = (HQ931LISTEN)dwInstance; P_LISTEN_OBJECT pListenObject = NULL; CS_STATUS CreateObjectResult; HQ931CALL hQ931Call; P_CALL_OBJECT pCallObject = NULL; HRESULT TempResult; DWORD dwPhysicalId;
Q931DBG((DBGTRACE, "Q931ListenCallback."));
if (dwMessage != LINK_CONNECT_REQUEST) { Q931DBG((DBGERROR, "unexpected callback received on listen socket")); return; }
if (FAILED(dwMessage)) { Q931DBG((DBGERROR, "error on listen socket")); return; }
if ((ListenObjectLock(hListenObject, &pListenObject) != CS_OK) || (pListenObject == NULL)) { Q931DBG((DBGERROR, "ListenObjectLock() returned error")); return; }
// create call object with all known attributes of this call.
// a handle of the call object is returned in phQ931Call.
CreateObjectResult = CallObjectCreate(&hQ931Call, pListenObject->dwUserToken, CC_INVALID_HANDLE, pListenObject->ListenCallback, FALSE, // I am NOT the caller.
LocalAddr, // Local address on which channel is connected
PeerAddr, // Address to which channel is connected
NULL, // Address of opposite call end-point.
NULL, // no source addr
NULL, // no conference id yet.
CSG_NONE, // no goal yet.
CC_CALLTYPE_UNKNOWN, // no call type yet.
FALSE, // caller is assumed to not be the MC.
NULL, // no display yet.
NULL, // no called party number yet.
NULL, // no caller aliases yet.
NULL, // no callee aliases yet.
NULL, // no extra aliases yet.
NULL, // no extension aliases.
NULL, // no EndpointType info yet.
NULL, 0, // no bandwidth yet
0); // no CRV yet.
if (CreateObjectResult != CS_OK) { Q931DBG((DBGERROR, "CallObjectCreate() failed.")); ListenObjectUnlock(pListenObject); return; }
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error")); ListenObjectUnlock(pListenObject); return; }
TempResult = linkLayerInit(&pCallObject->dwPhysicalId, hQ931Call, Q931ReceiveCallback, Q931SendComplete); if (FAILED(TempResult)) { Q931DBG((DBGERROR, "linkLayerInit() failed")); CallObjectDestroy(pCallObject); ListenObjectUnlock(pListenObject); return; }
// pCallObject->bCallState = CALLSTATE_NULL;
// unlock CallObject before calling down into h245ws in order to prevent deadlock - which
// is probably unlikely with linkLayerAccept(), but just to be safe and consistent...
// not sure if we need to worry about unlocking the listen object???
dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject);
TempResult = linkLayerAccept(pListenObject->dwPhysicalId, dwPhysicalId, Q931ConnectCallback);
if (FAILED(TempResult)) { if((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { ListenObjectUnlock(pListenObject); return; } Q931DBG((DBGERROR, "linkLayerAccept() failed")); { DWORD dwId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); } ListenObjectUnlock(pListenObject); return; }
ListenObjectUnlock(pListenObject); }
//====================================================================================
//
// PUBLIC FUNCTIONS
//
//====================================================================================
//====================================================================================
//====================================================================================
CS_STATUS Q931Init() { CS_STATUS result;
if (bQ931Initialized == TRUE) { ASSERT(FALSE); return CS_DUPLICATE_INITIALIZE; }
bQ931Initialized = TRUE;
// Register Call Setup for debug output
ISRREGISTERMODULE(&ghISRInst, "Q931", "Q931 Call Setup");
// Initialize the current conference ID to 0's, which is intentionally
// assigned to an invalid conference ID. Must create one for it
// to be valid.
memset(&(ConferenceIDSource), 0, sizeof(ConferenceIDSource));
__try {
InitializeCriticalSectionAndSpinCount(&(ConferenceIDSource.Lock),H323_SPIN_COUNT);
} __except ((GetExceptionCode() == STATUS_NO_MEMORY) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
// failure
return CS_NO_MEMORY; }
if ((result = ListenListCreate()) != CS_OK) { return result; } if ((result = CallListCreate()) != CS_OK) { ListenListDestroy(); return result; }
#if (defined(_DEBUG) && defined(PCS_COMPLIANCE))
Q931Logger = InteropLoad(Q931LOG_PROTOCOL); #endif
return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931DeInit() { CS_STATUS result1; CS_STATUS result2;
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
#if (defined(_DEBUG) && defined(PCS_COMPLIANCE))
// This causes a protection exception, so don't do it for now. DAC 12/9/96
// InteropUnload(Q931Logger);
#endif
result1 = ListenListDestroy();
result2 = CallListDestroy();
DeleteCriticalSection(&(ConferenceIDSource.Lock));
bQ931Initialized = FALSE;
if (result1 != CS_OK) { return result1; } return result2; }
//====================================================================================
//====================================================================================
CS_STATUS Q931Listen( PHQ931LISTEN phQ931Listen, PCC_ADDR pListenAddr, DWORD dwListenToken, Q931_CALLBACK ListenCallback) { CS_STATUS CreateObjectResult; P_LISTEN_OBJECT pListenObject = NULL; HRESULT TempResult;
// make sure q931 is initialized with an initialize flag.
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
// make sure parms are validated.
if ((phQ931Listen == NULL) || (ListenCallback == NULL) || (pListenAddr == NULL)) { ASSERT(FALSE); return CS_BAD_PARAM; }
SetDefaultPort(pListenAddr);
// create listen object with all known attributes of this listen session.
// a handle of the listen object is returned in phQ931Listen.
CreateObjectResult = ListenObjectCreate(phQ931Listen, dwListenToken, ListenCallback); if (CreateObjectResult != CS_OK) { return CS_SUBSYSTEM_FAILURE; }
if (ListenObjectLock(*phQ931Listen, &pListenObject) != CS_OK) { return CS_BAD_PARAM; }
TempResult = linkLayerListen(&pListenObject->dwPhysicalId, *phQ931Listen, pListenAddr, Q931ListenCallback); ListenObjectUnlock(pListenObject); if (FAILED(TempResult)) { Q931DBG((DBGERROR, "Q931Listen() linkLayerListen failed.")); return TempResult; }
Q931DBG((DBGTRACE, "Q931Listen() completed successfully.")); return CS_OK; }
//====================================================================================
// In the old code, this blocked until thread and socket were finished
// closing...
//====================================================================================
CS_STATUS Q931CancelListen( HQ931LISTEN hQ931Listen) { P_LISTEN_OBJECT pListenObject = NULL; CS_STATUS Status;
// make sure q931 is initialized with an initialize flag.
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Q931CancelListen() finding listen object..."));
// lock the listen object, get the event to wait for, and unlock the listen object.
if (ListenObjectLock(hQ931Listen, &pListenObject) != CS_OK) { return CS_BAD_PARAM; }
{ DWORD dwId = pListenObject->dwPhysicalId; linkLayerShutdown(dwId); // destroy the object. dont need to unlock it since entire object will be destroyed.
Q931DBG((DBGTRACE, "Q931CancelListen(): destroying listen object...")); Status = ListenObjectDestroy(pListenObject); }
return Status; }
//====================================================================================
//====================================================================================
CS_STATUS Q931PlaceCall( PHQ931CALL phQ931Call, LPWSTR pszDisplay, PCC_ALIASNAMES pCallerAliasList, PCC_ALIASNAMES pCalleeAliasList, PCC_ALIASNAMES pExtraAliasList, PCC_ALIASITEM pExtensionAliasItem, PCC_NONSTANDARDDATA pNonStandardData, PCC_ENDPOINTTYPE pSourceEndpointType, LPWSTR pszCalledPartyNumber, PCC_ADDR pControlAddr, PCC_ADDR pDestinationAddr, PCC_ADDR pSourceAddr, BOOL bCallerIsMC, CC_CONFERENCEID *pConferenceID, WORD wGoal, WORD wCallType, DWORD dwUserToken, Q931_CALLBACK ConnectCallback, DWORD dwBandwidth, WORD wCRV) { CS_STATUS CreateObjectResult; P_CALL_OBJECT pCallObject = NULL; CC_ADDR PeerCallAddr; CC_ADDR PeerConnectAddr; CC_ADDR SourceAddr; HRESULT TempResult; char szAsciiDisplay[CC_MAX_DISPLAY_LENGTH + 1]; char szAsciiPartyNumber[CC_MAX_PARTY_NUMBER_LEN + 1]; DWORD dwPhysicalId;
// make sure q931 is initialized with an initialize flag.
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
// make sure parms are validated.
if ((phQ931Call == NULL) || (ConnectCallback == NULL) || ((pControlAddr == NULL) && (pDestinationAddr == NULL)) || (pSourceEndpointType == NULL)) { return CS_BAD_PARAM; }
{ CS_STATUS TempStatus;
TempStatus = Q931ValidateAddr(pControlAddr); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateAddr(pDestinationAddr); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateAddr(pSourceAddr); if (TempStatus != CS_OK) { return TempStatus; }
TempStatus = Q931ValidateVendorInfo(pSourceEndpointType->pVendorInfo); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateDisplay(pszDisplay); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidatePartyNumber(pszCalledPartyNumber); if (TempStatus != CS_OK) { return TempStatus; }
szAsciiDisplay[0] = '\0'; if (pszDisplay && WideCharToMultiByte(CP_ACP, 0, pszDisplay, -1, szAsciiDisplay, sizeof(szAsciiDisplay), NULL, NULL) == 0) { return CS_BAD_PARAM; } szAsciiPartyNumber[0] = '\0'; if (pszCalledPartyNumber && WideCharToMultiByte(CP_ACP, 0, pszCalledPartyNumber, -1, szAsciiPartyNumber, sizeof(szAsciiPartyNumber), NULL, NULL) == 0) { return CS_BAD_PARAM; } TempStatus = Q931ValidateNonStandardData(pNonStandardData); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateAliasNames(pCallerAliasList); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateAliasNames(pCalleeAliasList); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateAliasNames(pExtraAliasList); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateAliasItem(pExtensionAliasItem); if (TempStatus != CS_OK) { return TempStatus; } }
// get the correct callee and control address to use for the call.
if (pDestinationAddr) { if (!MakeBinaryADDR(pDestinationAddr, &PeerCallAddr)) { return CS_BAD_PARAM; } SetDefaultPort(&PeerCallAddr); }
if (pControlAddr) { if (!MakeBinaryADDR(pControlAddr, &PeerConnectAddr)) { return CS_BAD_PARAM; } SetDefaultPort(&PeerConnectAddr); } else { PeerConnectAddr = PeerCallAddr; }
// get the correct callee and control address to use for the call.
if (pSourceAddr) { if (!MakeBinaryADDR(pSourceAddr, &SourceAddr)) { return CS_BAD_PARAM; } SetDefaultPort(&SourceAddr); }
if (wGoal == CSG_CREATE) { // caller is asking to start a new conference.
if (((DWORD *)pConferenceID->buffer)[0] == 0 && ((DWORD *)pConferenceID->buffer)[1] == 0 && ((DWORD *)pConferenceID->buffer)[2] == 0 && ((DWORD *)pConferenceID->buffer)[3] == 0) { _ConferenceIDNew(pConferenceID); } }
// create call object with all known attributes of this call.
// a handle of the call object is returned in phQ931Call.
CreateObjectResult = CallObjectCreate(phQ931Call, CC_INVALID_HANDLE, dwUserToken, ConnectCallback, TRUE, // I am the caller.
NULL, // no local address yet.
&PeerConnectAddr, pDestinationAddr ? &PeerCallAddr : NULL, pSourceAddr ? &SourceAddr : NULL, pConferenceID, wGoal, wCallType, bCallerIsMC, pszDisplay ? szAsciiDisplay : NULL, pszCalledPartyNumber ? szAsciiPartyNumber : NULL, pCallerAliasList, pCalleeAliasList, pExtraAliasList, pExtensionAliasItem, pSourceEndpointType, pNonStandardData, dwBandwidth, wCRV);
if (CreateObjectResult != CS_OK) { return CS_SUBSYSTEM_FAILURE; }
if ((CallObjectLock(*phQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error")); return CS_SUBSYSTEM_FAILURE; }
TempResult = linkLayerInit(&pCallObject->dwPhysicalId, *phQ931Call, Q931ReceiveCallback, Q931SendComplete); if (FAILED(TempResult)) { Q931DBG((DBGERROR, "linkLayerInit() failed")); CallObjectDestroy(pCallObject); *phQ931Call = 0; return TempResult; }
// unlock CallObject before calling down into h245ws in order to prevent deadlock - which
// is probably unlikely with linkLayerConnect(), but just to be safe and consistent...
dwPhysicalId = pCallObject->dwPhysicalId; CallObjectUnlock(pCallObject); TempResult = linkLayerConnect(dwPhysicalId, &PeerConnectAddr, Q931ConnectCallback); if((CallObjectLock(*phQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { *phQ931Call = 0; return(CS_INTERNAL_ERROR); }
if (FAILED(TempResult)) { Q931DBG((DBGERROR, "linkLayerConnect() failed")); { DWORD dwId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); } *phQ931Call = 0; return TempResult; }
// pCallObject->bCallState = CALLSTATE_NULL;
CallObjectUnlock(pCallObject);
Q931DBG((DBGTRACE, "Q931PlaceCall() completed successfully.")); return CS_OK; }
//====================================================================================
// In the old code, this blocked until thread and socket were finished
// closing...
//====================================================================================
CS_STATUS Q931Hangup( HQ931CALL hQ931Call, BYTE bReason) { P_CALL_OBJECT pCallObject = NULL; CS_STATUS Status;
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Entering Q931Hangup()..."));
// need parameter checking...
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGTRACE, "Call Object no longer available: 0x%08lx", hQ931Call)); return CS_BAD_PARAM; }
{ CS_STATUS SendStatus = CS_OK; if (pCallObject->bCallState != CALLSTATE_NULL) { // send the RELEASE COMPLETE message to the peer to hang-up.
SendStatus = Q931SendReleaseCompleteMessage(pCallObject, bReason, &(pCallObject->ConferenceID), NULL, NULL); }
{ DWORD dwId = pCallObject->dwPhysicalId; Status = CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); }
if (FAILED(SendStatus)) { return SendStatus; } }
return Status; }
//====================================================================================
//====================================================================================
CS_STATUS Q931AcceptCall( HQ931CALL hQ931Call, LPWSTR pszDisplay, PCC_NONSTANDARDDATA pNonStandardData, PCC_ENDPOINTTYPE pDestinationEndpointType, PCC_ADDR pH245Addr, DWORD dwBandwidth, DWORD dwUserToken) { P_CALL_OBJECT pCallObject = NULL; CS_STATUS result = CS_OK; char szAsciiDisplay[CC_MAX_DISPLAY_LENGTH + 1];
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Entering Q931AcceptCall()..."));
if ((pDestinationEndpointType == NULL) || (pDestinationEndpointType->pVendorInfo == NULL)) { return CS_BAD_PARAM; }
{ CS_STATUS TempStatus;
TempStatus = Q931ValidateVendorInfo(pDestinationEndpointType->pVendorInfo); if (TempStatus != CS_OK) { return TempStatus; } TempStatus = Q931ValidateDisplay(pszDisplay); if (TempStatus != CS_OK) { return TempStatus; } szAsciiDisplay[0] = '\0'; if (pszDisplay && WideCharToMultiByte(CP_ACP, 0, pszDisplay, -1, szAsciiDisplay, sizeof(szAsciiDisplay), NULL, NULL) == 0) { return CS_BAD_PARAM; } TempStatus = Q931ValidateNonStandardData(pNonStandardData); if (TempStatus != CS_OK) { return TempStatus; } }
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error (Socket not found).")); return CS_INTERNAL_ERROR; }
if (pCallObject->fIsCaller) { Q931DBG((DBGERROR, "Caller attempted to accept call."));
CallObjectUnlock(pCallObject); return CS_OUT_OF_SEQUENCE; }
// label with the user supplied UserToken for this call object.
pCallObject->dwUserToken = dwUserToken; pCallObject->dwBandwidth = dwBandwidth;
// send the CONNECT message to peer to accept call.
{ DWORD CodedLengthASN; BYTE *CodedPtrASN; HRESULT ResultASN = CS_OK; CC_ADDR h245Addr;
if (pH245Addr != NULL) { MakeBinaryADDR(pH245Addr, &h245Addr); }
ResultASN = Q931ConnectEncodeASN(pNonStandardData, &(pCallObject->ConferenceID), (pH245Addr ? &h245Addr : NULL), pDestinationEndpointType, &pCallObject->World, &CodedPtrASN, &CodedLengthASN); if ((ResultASN != CS_OK) || (CodedLengthASN == 0) || (CodedPtrASN == NULL)) { Q931DBG((DBGERROR, "Q931ConnectEncodeASN() failed, nothing to send.")); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } CallObjectUnlock(pCallObject); return CS_SUBSYSTEM_FAILURE; } else { DWORD CodedLengthPDU; BYTE *CodedPtrPDU; BINARY_STRING UserUserData; HRESULT ResultEncode = CS_OK; HRESULT TempResult; WORD wCRV = (WORD)(pCallObject->wCRV | 0x8000);
UserUserData.length = (WORD)CodedLengthASN; UserUserData.ptr = CodedPtrASN;
ResultEncode = Q931ConnectEncodePDU(wCRV, szAsciiDisplay, pCallObject->dwBandwidth, &UserUserData, &CodedPtrPDU, &CodedLengthPDU); if (CodedPtrASN != NULL) { Q931FreeEncodedBuffer(&pCallObject->World, CodedPtrASN); } if ((ResultEncode != CS_OK) || (CodedLengthPDU == 0) || (CodedPtrPDU == NULL)) { Q931DBG((DBGERROR, "Q931ConnectEncodePDU() failed, nothing to send.")); if (CodedPtrPDU != NULL) { Free(CodedPtrPDU); } CallObjectUnlock(pCallObject); return CS_SUBSYSTEM_FAILURE; }
TempResult = Q931SendMessage(pCallObject, CodedPtrPDU, CodedLengthPDU, TRUE); if (CallObjectValidate(hQ931Call) != CS_OK) return CS_INTERNAL_ERROR;
if (FAILED(TempResult)) { Q931DBG((DBGERROR, "datalinkSendRequest() failed"));
// when the connect notification fails...what should we do anyway????
CallObjectUnlock(pCallObject); return TempResult; } } }
pCallObject->bCallState = CALLSTATE_ACTIVE;
CallObjectUnlock(pCallObject); return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931RejectCall( HQ931CALL hQ931Call, BYTE bRejectReason, PCC_CONFERENCEID pConferenceID, PCC_ADDR pAlternateAddr, PCC_NONSTANDARDDATA pNonStandardData) { P_CALL_OBJECT pCallObject = NULL; CS_STATUS result = CS_OK; CS_STATUS Status = CS_OK;
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Entering Q931RejectCall()..."));
{ CS_STATUS TempStatus;
TempStatus = Q931ValidateNonStandardData(pNonStandardData); if (TempStatus != CS_OK) { return TempStatus; } }
// if reason is alternate addr, but there is no alternate addr -->err
if (((bRejectReason == CC_REJECT_ROUTE_TO_GATEKEEPER) || (bRejectReason == CC_REJECT_CALL_FORWARDED) || (bRejectReason == CC_REJECT_ROUTE_TO_MC)) && (pAlternateAddr == NULL)) { return CS_BAD_PARAM; }
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error (Socket not found).")); return CS_INTERNAL_ERROR; }
if (pCallObject->fIsCaller) { Q931DBG((DBGERROR, "Caller attempted to reject call."));
CallObjectUnlock(pCallObject); return CS_OUT_OF_SEQUENCE; }
result = Q931SendReleaseCompleteMessage(pCallObject, bRejectReason, pConferenceID, pAlternateAddr, pNonStandardData);
{ DWORD dwId = pCallObject->dwPhysicalId; Status = CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); }
if (result != CS_OK) { return result; }
return Status; }
//====================================================================================
//====================================================================================
CS_STATUS Q931ReOpenConnection( HQ931CALL hQ931Call) { P_CALL_OBJECT pCallObject = NULL; HRESULT TempResult = CS_OK; CC_ADDR PeerConnectAddr; DWORD dwPhysicalId;
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Entering Q931ReOpenConnection()..."));
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGERROR, "CallObjectLock() returned error.")); return CS_INTERNAL_ERROR; }
if (pCallObject->bConnected) { return CS_OUT_OF_SEQUENCE; }
Q931MakePhysicalID(&pCallObject->dwPhysicalId); TempResult = linkLayerInit(&pCallObject->dwPhysicalId, hQ931Call, Q931ReceiveCallback, Q931SendComplete); if (FAILED(TempResult)) { Q931DBG((DBGERROR, "linkLayerInit() failed on re-connect.")); CallObjectUnlock(pCallObject); return TempResult; }
// unlock CallObject before calling down into h245ws in order to prevent deadlock - which
// is probably unlikely with linkLayerConnect, but just to be safe and consistent...
// copy stuff we need out of call object before we unlock it
dwPhysicalId = pCallObject->dwPhysicalId; PeerConnectAddr = pCallObject->PeerConnectAddr;
CallObjectUnlock(pCallObject);
TempResult = linkLayerConnect(dwPhysicalId, &PeerConnectAddr, Q931ConnectCallback);
if((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { return(CS_INTERNAL_ERROR); }
if (FAILED(TempResult)) { Q931DBG((DBGERROR, "linkLayerConnect() failed on re-connect.")); linkLayerShutdown(pCallObject->dwPhysicalId); CallObjectUnlock(pCallObject); return TempResult; }
CallObjectUnlock(pCallObject);
Q931DBG((DBGTRACE, "Q931ReOpenConnection() completed successfully.")); return CS_OK; }
//====================================================================================
//====================================================================================
CS_STATUS Q931GetVersion( WORD wLength, LPWSTR pszVersion) { WCHAR pszQ931Version[255];
// parameter validation.
if ((wLength == 0) || (pszVersion == NULL)) { return CS_BAD_PARAM; }
wcscpy(pszQ931Version, L"Call Setup "); wcscat(pszQ931Version, Unicode(__DATE__)); wcscat(pszQ931Version, L" "); wcscat(pszQ931Version, Unicode(__TIME__));
if (wcslen(pszQ931Version) >= wLength) { memcpy(pszVersion, pszQ931Version, (wLength-1)*sizeof(WCHAR)); pszQ931Version[wLength-1] = L'\0'; return CS_BAD_SIZE; }
wcscpy(pszVersion, pszQ931Version); return CS_OK; }
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Timer Routines...
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//====================================================================================
// Timer 301 has expired for this object...
//====================================================================================
void CallBackT301(P_CALL_OBJECT pCallObject) { CSS_CALL_FAILED EventData; HQ931CALL hQ931Call = pCallObject->hQ931Call;
EventData.error = CS_RINGING_TIMER_EXPIRED; pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData);
if (CallObjectValidate(hQ931Call) == CS_OK) { if (Q931SendReleaseCompleteMessage(pCallObject, CC_REJECT_TIMER_EXPIRED, NULL, NULL, NULL) == CS_OK) { // nothing to do...
} { DWORD dwId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); } } return; }
//====================================================================================
// Timer 303 has expired for this object...
//====================================================================================
void CallBackT303(P_CALL_OBJECT pCallObject) { CSS_CALL_FAILED EventData; HQ931CALL hQ931Call = pCallObject->hQ931Call;
EventData.error = CS_SETUP_TIMER_EXPIRED; pCallObject->Callback(Q931_CALL_FAILED, pCallObject->hQ931Call, pCallObject->dwListenToken, pCallObject->dwUserToken, &EventData);
if (CallObjectValidate(hQ931Call) == CS_OK) { if (Q931SendReleaseCompleteMessage(pCallObject, CC_REJECT_TIMER_EXPIRED, NULL, NULL, NULL) == CS_OK) { // nothing to do...
} { DWORD dwId = pCallObject->dwPhysicalId; CallObjectDestroy(pCallObject); linkLayerShutdown(dwId); } } return; }
//====================================================================================
//====================================================================================
void Q931SetReceivePDUHook(Q931_RECEIVE_PDU_CALLBACK Q931ReceivePDUCallback) { gReceivePDUHookProc = Q931ReceivePDUCallback; return; }
//====================================================================================
//====================================================================================
CS_STATUS Q931FlushSendQueue( HQ931CALL hQ931Call) { P_CALL_OBJECT pCallObject = NULL; HRESULT TempResult = CS_OK; DWORD dwPhysicalId;
if (bQ931Initialized == FALSE) { return CS_NOT_INITIALIZED; }
Q931DBG((DBGTRACE, "Entering Q931FlushSendQueue()..."));
// need parameter checking...
if ((CallObjectLock(hQ931Call, &pCallObject) != CS_OK) || (pCallObject == NULL)) { Q931DBG((DBGTRACE, "Call Object no longer available: 0x%08lx", hQ931Call)); return CS_INTERNAL_ERROR; }
dwPhysicalId = pCallObject->dwPhysicalId;
CallObjectUnlock(pCallObject);
TempResult = linkLayerFlushChannel(dwPhysicalId, DATALINK_TRANSMIT); if (FAILED(TempResult)) { Q931DBG((DBGERROR, "datalinkSendRequest() failed")); }
return(TempResult); }
#ifdef __cplusplus
} #endif
|