/*++ Copyright (c) 1999 Microsoft Corporation Module Name: call.cpp Abstract: TAPI Service Provider functions related to manipulating calls. TSPI_lineAnswer TSPI_lineCloseCall TSPI_lineDrop TSPI_lineGetCallAddressID TSPI_lineGetCallInfo TSPI_lineGetCallStatus TSPI_lineMakeCall TSPI_lineMonitorDigits TSPI_lineSendUserUserInfo TSPI_lineReleaseUserUserInfo Author: Nikhil Bobde (NikhilB) Revision History: --*/ // // Include files // #include "globals.h" #include "line.h" #include "q931pdu.h" #include "q931obj.h" #include "ras.h" #include "config.h" #define SETUP_SENT_TIMEOUT 8000 #define H450_ENCODED_ARG_LEN 0x4000 #define MAX_DIVERSION_COUNTER 14 static LONG g_H323CallID; static LONG g_lNumberOfcalls; LONG g_lCallReference; // // Public functions // // //The function that handles a network event(CONNECT|CLOSE) on any of the //Q931 calls. This function needs to find out the exact event // that took place and the socket on which it took place // void NTAPI Q931TransportEventHandler ( IN PVOID Parameter, IN BOOLEAN TimerFired) { PH323_CALL pCall; H323DBG(( DEBUG_LEVEL_TRACE, "Q931 transport event recvd." )); pCall = g_pH323Line -> FindH323CallAndLock ((HDRVCALL) Parameter); if( pCall != NULL ) { pCall -> HandleTransportEvent(); pCall -> Unlock(); } } // // returns S_OK if socket was consumed // returns E_FAIL if socket should be destroyed by caller // static HRESULT CallCreateIncomingCall ( IN SOCKET Socket, IN SOCKADDR_IN * LocalAddress, IN SOCKADDR_IN * RemoteAddress) { PH323_CALL pCall; HANDLE SelectEvent; HANDLE SelectWaitHandle; BOOL fSuccess = TRUE; BOOL DeleteCall = FALSE; TCHAR ptstrEventName[100]; BOOL retVal; pCall = new CH323Call; if( pCall == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "failed to allocate memory for CH323Call." )); return E_OUTOFMEMORY; } _stprintf( ptstrEventName, _T("%s-%p"), _T( "H323TSP_Incoming_TransportHandlerEvent" ), pCall ); // create the wait event SelectEvent = H323CreateEvent (NULL, FALSE, FALSE, ptstrEventName ); if( SelectEvent == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "CALL: failed to create select event." )); delete pCall; return GetLastResult(); } retVal = pCall -> Initialize( NULL, LINECALLORIGIN_INBOUND, CALLTYPE_NORMAL ); if( retVal == FALSE ) { H323DBG ((DEBUG_LEVEL_ERROR, "failed to initialize CH323Call.")); CloseHandle (SelectEvent); delete pCall; return E_FAIL; } //add it to the call context array if (!pCall -> InitializeQ931 (Socket)) { H323DBG(( DEBUG_LEVEL_ERROR, "Failed to initialize incoming call Q.931 state." )); DeleteCall = FALSE; pCall -> Shutdown (&DeleteCall); delete pCall; if (SelectEvent) { CloseHandle (SelectEvent); } return E_FAIL; } pCall -> SetQ931CallState (Q931_CALL_CONNECTED); pCall -> Lock(); if (!RegisterWaitForSingleObject( &SelectWaitHandle, // pointer to the returned handle. SelectEvent, // the event handle to wait for. Q931TransportEventHandler, // the callback function. (PVOID)pCall -> GetCallHandle(),// the context for the callback. INFINITE, // wait forever. WT_EXECUTEDEFAULT)) // use the wait thread to call the callback. { goto cleanup; } _ASSERTE( SelectWaitHandle ); if( SelectWaitHandle == NULL ) { goto cleanup; } //store this in the call context pCall -> SetNewCallInfo (SelectWaitHandle, SelectEvent, Q931_CALL_CONNECTED); SelectEvent = NULL; pCall -> InitializeRecvBuf(); //post a buffer to winsock to accept messages from the peer if(!pCall -> PostReadBuffer()) { H323DBG(( DEBUG_LEVEL_ERROR, "failed to post read buffer on call." )); goto cleanup; } pCall -> Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "successfully created incoming Q.931 call." )); //success return S_OK; cleanup: if (pCall) { pCall -> Unlock(); pCall -> Shutdown (&DeleteCall); delete pCall; } if (SelectEvent) { CloseHandle (SelectEvent); } return E_OUTOFMEMORY; } void CallProcessIncomingCall ( IN SOCKET Socket, IN SOCKADDR_IN * LocalAddress, IN SOCKADDR_IN * RemoteAddress) { HRESULT hr; hr = CallCreateIncomingCall (Socket, LocalAddress, RemoteAddress); if (hr != S_OK) { closesocket (Socket); } } #if DBG DWORD ProcessTAPICallRequest( IN PVOID ContextParameter ) { __try { return ProcessTAPICallRequestFre( ContextParameter ); } __except( 1 ) { TAPI_CALLREQUEST_DATA* pRequestData = (TAPI_CALLREQUEST_DATA*)ContextParameter; H323DBG(( DEBUG_LEVEL_TRACE, "TSPI %s event threw exception: %p, %p.", EventIDToString(pRequestData -> EventID), pRequestData -> pCall, pRequestData -> pCallforwardParams )); _ASSERTE( FALSE ); return 0; } } #endif DWORD ProcessTAPICallRequestFre( IN PVOID ContextParameter) { _ASSERTE( ContextParameter ); TAPI_CALLREQUEST_DATA* pCallRequestData = (TAPI_CALLREQUEST_DATA*)ContextParameter; PH323_CALL pCall = pCallRequestData->pCall; BOOL fDelete = FALSE; H323DBG(( DEBUG_LEVEL_TRACE, "TSPI %s event recvd.", EventIDToString(pCallRequestData -> EventID) )); pCall -> Lock(); if( pCallRequestData -> EventID == TSPI_DELETE_CALL ) { pCall -> Unlock(); delete pCallRequestData; delete pCall; return EXIT_SUCCESS; } if( pCall -> IsCallShutdown() == FALSE ) { switch( pCallRequestData -> EventID ) { case TSPI_MAKE_CALL: pCall -> MakeCall(); break; case TSPI_ANSWER_CALL: pCall -> AcceptCall(); break; case TSPI_DROP_CALL: pCall -> DropUserInitiated( 0 ); //pCall -> DropCall(0); break; case TSPI_RELEASE_U2U: pCall -> ReleaseU2U(); break; case TSPI_CALL_HOLD: pCall -> Hold(); break; case TSPI_CALL_UNHOLD: pCall -> UnHold(); break; case TSPI_CALL_DIVERT: pCall -> CallDivertOnNoAnswer(); break; case TSPI_LINEFORWARD_NOSPECIFIC: case TSPI_LINEFORWARD_SPECIFIC: pCall -> Forward( pCallRequestData -> EventID, pCallRequestData -> pCallforwardParams ); break; case TSPI_SEND_U2U: pCall -> SendU2U( pCallRequestData -> pBuf->pbBuffer, pCallRequestData->pBuf->dwLength ); delete pCallRequestData -> pBuf; break; default: _ASSERTE(0); break; } } pCall -> DecrementIoRefCount( &fDelete ); pCall -> Unlock(); delete pCallRequestData; if( fDelete == TRUE ) { H323DBG((DEBUG_LEVEL_TRACE, "call delete:%p.", pCall )); delete pCall; } return EXIT_SUCCESS; } // // CH323Call Methods // CH323Call::CH323Call(void) { ZeroMemory( (PVOID)this, sizeof(CH323Call) ); /*m_dwFlags = 0; m_pwszDisplay = NULL; m_fMonitoringDigits = FALSE; m_hdCall = NULL; m_htCall = NULL; m_dwCallState = NULL; m_dwOrigin = NULL; m_dwAddressType = NULL; m_dwIncomingModes = NULL; m_dwOutgoingModes = NULL; m_dwRequestedModes = NULL; // requested media modes m_hdMSPLine = NULL; m_htMSPLine = NULL; //m_fGateKeeperPresent = FALSE; m_fReadyToAnswer = FALSE; m_fCallAccepted = FALSE; // reset addresses memset((PVOID)&m_CalleeAddr,0,sizeof(H323_ADDR)); memset((PVOID)&m_CallerAddr,0,sizeof(H323_ADDR)); // reset addresses m_pCalleeAliasNames = NULL; m_pCallerAliasNames = NULL; //reset non standard data memset( (PVOID)&m_NonStandardData, 0, sizeof(H323NonStandardData ) ); //reset the conference ID ZeroMemory (&m_ConferenceID, sizeof m_ConferenceID); pFastStart = NULL; //redet the peer information memset( (PVOID)&m_peerH245Addr, 0, sizeof(H323_ADDR) ); memset( (PVOID)&m_selfH245Addr, 0, sizeof(H323_ADDR) ); memset( (PVOID)&m_peerNonStandardData, 0, sizeof(H323NonStandardData ) ); memset( (PVOID)&m_peerVendorInfo, 0, sizeof(H323_VENDORINFO) ); memset( (PVOID)&m_peerEndPointType, 0, sizeof(H323_ENDPOINTTYPE) ); m_pPeerFastStart = NULL; m_pPeerExtraAliasNames = NULL; m_pPeerDisplay = NULL; m_hCallEstablishmentTimer = NULL; m_hCallDivertOnNATimer = NULL; //Q931call data m_hTransport = NULL; m_hTransportWait = NULL; pRecvBuf = NULL; m_hSetupSentTimer = NULL; m_dwStateMachine = 0; m_dwQ931Flags = 0; // fActiveMC = FALSE; memset( (PVOID)&m_ASNCoderInfo, 0, sizeof(m_ASNCoderInfo)); m_wCallReference = NULL; m_wQ931CallRef = NULL; m_IoRefCount = 0; //RAS call data wARQSeqNum = 0; m_wDRQSeqNum = 0; m_pARQExpireContext = NULL; m_pDRQExpireContext= NULL; m_hARQTimer = NULL; m_hDRQTimer = NULL; m_dwDRQRetryCount = 0; m_dwARQRetryCount = 0; m_fCallInTrnasition = FALSE m_dwAppSpecific = 0;*/ m_dwFastStart = FAST_START_UNDECIDED; m_callSocket = INVALID_SOCKET; m_bStartOfPDU = TRUE; H323DBG(( DEBUG_LEVEL_TRACE, "Initialize:m_IoRefCount:%d:%p.", m_IoRefCount, this )); m_dwRASCallState = RASCALL_STATE_IDLE; if( InterlockedIncrement( &g_lNumberOfcalls ) == 1 ) { H323DBG(( DEBUG_LEVEL_TRACE, "pCall no goes from 0 to 1:g_hCanUnloadDll set.", this )); ResetEvent( g_hCanUnloadDll ); } H323DBG(( DEBUG_LEVEL_TRACE, "New pCall object created:%p.", this )); } CH323Call::~CH323Call() { CALL_SEND_CONTEXT* pSendBuf; PLIST_ENTRY pLE; H323DBG(( DEBUG_LEVEL_ERROR, "pCall object deleted:%p.", this )); if( m_dwFlags & CALLOBJECT_INITIALIZED ) { while( IsListEmpty( &m_sendBufList ) == FALSE ) { pLE = RemoveHeadList( &m_sendBufList ); pSendBuf = CONTAINING_RECORD( pLE, CALL_SEND_CONTEXT, ListEntry); delete pSendBuf->WSABuf.buf; delete pSendBuf; } if( m_hTransportWait != NULL ) { if( UnregisterWaitEx( m_hTransportWait, NULL ) == FALSE ) { GetLastError(); } m_hTransportWait = NULL; } if( m_hTransport != NULL ) { if(!CloseHandle(m_hTransport)) { WSAGetLastError(); } m_hTransport = NULL; } if( m_callSocket != INVALID_SOCKET ) { closesocket( m_callSocket ); m_callSocket = INVALID_SOCKET; } TermASNCoder(); DeleteCriticalSection( &m_CriticalSection ); } if( InterlockedDecrement( &g_lNumberOfcalls ) == 0 ) { H323DBG(( DEBUG_LEVEL_ERROR, "Unload dll event set.%p.", this )); SetEvent( g_hCanUnloadDll ); } } //!!no need to lock BOOL CH323Call::Initialize( IN HTAPICALL htCall, IN DWORD dwOrigin, IN DWORD dwCallType ) { int index; int rc; H323DBG(( DEBUG_LEVEL_ERROR, "call init entered:%p.",this )); m_pCallerAliasNames = new H323_ALIASNAMES; if( m_pCallerAliasNames == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate caller name." )); return FALSE; } memset( (PVOID)m_pCallerAliasNames, 0, sizeof(H323_ALIASNAMES) ); //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); m_pCalleeAliasNames = new H323_ALIASNAMES; if( m_pCalleeAliasNames == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate callee name." )); goto error1; } memset( (PVOID)m_pCalleeAliasNames, 0, sizeof(H323_ALIASNAMES) ); __try { if( !InitializeCriticalSectionAndSpinCount( &m_CriticalSection, 0x80000000 ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "couldn't alloc critsec for call." )); goto error2; } } __except( 1 ) { goto error2; } if( dwOrigin == LINECALLORIGIN_OUTBOUND ) { int iresult = UuidCreate( &m_callIdentifier ); if( (iresult != RPC_S_OK) && (iresult !=RPC_S_UUID_LOCAL_ONLY) ) { goto error3; } } rc = InitASNCoder(); if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_ERROR, "Q931_InitCoder() returned: %d ", rc)); goto error3; } rc = InitH450ASNCoder(); if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_ERROR, "Q931_InitCoder() returned: %d ", rc)); goto error4; } //Create the CRV for this call. do { m_wCallReference = ((WORD)InterlockedIncrement( &g_lCallReference )) & 0x7fff; } while( (m_wCallReference == 0) || g_pH323Line->CallReferenceDuped( m_wCallReference ) ); //add the call to the call table index = g_pH323Line -> AddCallToTable((PH323_CALL)this); if( index == -1 ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not add call to call table." )); goto error5; } //By incrementing the g_H323CallID and taking lower 16 bits we get 65536 //unique values and then same values are repeated. Thus we can have only //65535 simultaneous calls. By using the call table index we make sure that //no two existing calls have same call handle. do { m_hdCall = (HDRVCALL)( ((BYTE*)NULL) + MAKELONG( LOWORD((DWORD)index), (WORD)InterlockedIncrement(&g_H323CallID) )); } while ( m_hdCall == NULL ); ZeroMemory( (PVOID)&m_prepareToAnswerMsgData, sizeof(BUFFERDESCR) ); m_dwFlags |= CALLOBJECT_INITIALIZED; m_htCall = htCall; m_dwCallState = LINECALLSTATE_IDLE; m_dwOrigin = dwOrigin; m_hdConf = NULL; m_wQ931CallRef = m_wCallReference; m_dwCallType = dwCallType; // initialize user user information InitializeListHead( &m_IncomingU2U ); InitializeListHead( &m_OutgoingU2U ); InitializeListHead( &m_sendBufList ); H323DBG(( DEBUG_LEVEL_TRACE, "m_hdCall:%lx m_htCall:%lx m_wCallReference:%lx : %p .", m_hdCall, m_htCall, m_wCallReference, this )); H323DBG(( DEBUG_LEVEL_TRACE, "call init exited:%p.",this )); return TRUE; error5: TermH450ASNCoder(); error4: TermASNCoder(); error3: DeleteCriticalSection( &m_CriticalSection ); error2: delete m_pCalleeAliasNames; m_pCalleeAliasNames = NULL; error1: delete m_pCallerAliasNames; m_pCallerAliasNames = NULL; return FALSE; } // //!!must be always called in a lock //Queues a request made by TAPI to the thread pool // BOOL CH323Call::QueueTAPICallRequest( IN DWORD EventID, IN PVOID pBuf ) { TAPI_CALLREQUEST_DATA * pCallRequestData = new TAPI_CALLREQUEST_DATA; BOOL fResult = TRUE; if( pCallRequestData != NULL ) { pCallRequestData -> EventID = EventID; pCallRequestData -> pCall = this; pCallRequestData -> pBuf = (PBUFFERDESCR)pBuf; if( !QueueUserWorkItem( ProcessTAPICallRequest, pCallRequestData, WT_EXECUTEDEFAULT ) ) { delete pCallRequestData; fResult = FALSE; } m_IoRefCount++; H323DBG(( DEBUG_LEVEL_TRACE, "TAPICallRequest:m_IoRefCount:%d:%p.", m_IoRefCount, this )); } else { fResult = FALSE; } return fResult; } //always called in lock void CH323Call::CopyCallStatus( IN LPLINECALLSTATUS pCallStatus ) { H323DBG(( DEBUG_LEVEL_ERROR, "CopyCallStatus entered:%p.",this )); // transer call state information pCallStatus->dwCallState = m_dwCallState; pCallStatus->dwCallStateMode = m_dwCallStateMode; // determine call feature based on state pCallStatus->dwCallFeatures = ( m_dwCallState != LINECALLSTATE_IDLE)? (H323_CALL_FEATURES) : 0; H323DBG(( DEBUG_LEVEL_ERROR, "CopyCallStatus exited:%p.",this )); } //always called in lock LONG CH323Call::CopyCallInfo( IN LPLINECALLINFO pCallInfo ) { DWORD dwCalleeNameSize = 0; DWORD dwCallerNameSize = 0; DWORD dwCallerAddressSize = 0; WCHAR wszIPAddress[20]; DWORD dwNextOffset = sizeof(LINECALLINFO); DWORD dwU2USize = 0; PBYTE pU2U = NULL; LONG retVal = NOERROR; DWORD dwDivertingNameSize = 0; DWORD dwDiversionNameSize = 0; DWORD dwDivertedToNameSize = 0; DWORD dwCallDataSize = 0; H323DBG(( DEBUG_LEVEL_ERROR, "CopyCallInfo entered:%p.",this )); // see if user user info available if( IsListEmpty( &m_IncomingU2U) == FALSE ) { PLIST_ENTRY pLE; PUserToUserLE pU2ULE; // get first list entry pLE = m_IncomingU2U.Flink; // convert to user user structure pU2ULE = CONTAINING_RECORD(pLE, UserToUserLE, Link); // transfer info dwU2USize = pU2ULE->dwU2USize; pU2U = pU2ULE->pU2U; } // initialize caller and callee id flags now pCallInfo->dwCalledIDFlags = LINECALLPARTYID_UNAVAIL; pCallInfo->dwCallerIDFlags = LINECALLPARTYID_UNAVAIL; pCallInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL; pCallInfo->dwRedirectionIDFlags = LINECALLPARTYID_UNAVAIL; // calculate memory necessary for strings if( m_pCalleeAliasNames && m_pCalleeAliasNames -> wCount !=0 ) { dwCalleeNameSize = H323SizeOfWSZ( m_pCalleeAliasNames -> pItems[0].pData ); } if( m_pCallerAliasNames && (m_pCallerAliasNames->wCount) ) { //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); dwCallerNameSize = sizeof(WCHAR) * (m_pCallerAliasNames->pItems[0].wDataLength + 1); } if( m_CallerAddr.Addr.IP_Binary.dwAddr != 0 ) { wsprintfW(wszIPAddress, L"%d.%d.%d.%d", (m_CallerAddr.Addr.IP_Binary.dwAddr >> 24) & 0xff, (m_CallerAddr.Addr.IP_Binary.dwAddr >> 16) & 0xff, (m_CallerAddr.Addr.IP_Binary.dwAddr >> 8) & 0xff, (m_CallerAddr.Addr.IP_Binary.dwAddr) & 0xff ); dwCallerAddressSize = (wcslen(wszIPAddress) + 1) * sizeof(WCHAR); } if( m_dwCallType & CALLTYPE_DIVERTEDDEST ) { if( m_pCallReroutingInfo->divertingNrAlias && (m_pCallReroutingInfo->divertingNrAlias->wCount !=0) ) { dwDivertingNameSize = H323SizeOfWSZ( m_pCallReroutingInfo->divertingNrAlias-> pItems[0].pData ); } if( m_pCallReroutingInfo->divertedToNrAlias && (m_pCallReroutingInfo->divertedToNrAlias->wCount != 0) ) { dwDivertedToNameSize = sizeof(WCHAR) * m_pCallReroutingInfo->divertedToNrAlias->pItems[0].wDataLength; } } if( m_dwCallType & CALLTYPE_DIVERTEDSRC_NOROUTING ) { if( m_pCallReroutingInfo->divertedToNrAlias && (m_pCallReroutingInfo->divertedToNrAlias->wCount != 0) ) { dwDivertedToNameSize = sizeof(WCHAR) * m_pCallReroutingInfo->divertedToNrAlias->pItems[0].wDataLength; } } if( m_dwCallType & CALLTYPE_DIVERTEDSRC) { if( m_pCallReroutingInfo->divertedToNrAlias && (m_pCallReroutingInfo->divertedToNrAlias->wCount != 0) ) { dwDivertedToNameSize = sizeof(WCHAR) * m_pCallReroutingInfo->divertedToNrAlias->pItems[0].wDataLength; } if( m_pCallReroutingInfo->divertingNrAlias && (m_pCallReroutingInfo->divertingNrAlias->wCount !=0) ) { dwDivertingNameSize = H323SizeOfWSZ( m_pCallReroutingInfo->divertingNrAlias-> pItems[0].pData ); } } if( m_CallData.wOctetStringLength != 0 ) { dwCallDataSize = m_CallData.wOctetStringLength; } // determine number of bytes needed pCallInfo->dwNeededSize = sizeof(LINECALLINFO) + dwCalleeNameSize + dwCallerNameSize + dwCallerAddressSize + dwDivertingNameSize + dwDiversionNameSize + dwDivertedToNameSize + dwU2USize + dwCallDataSize ; // see if structure size is large enough if (pCallInfo->dwTotalSize >= pCallInfo->dwNeededSize) { // record number of bytes used pCallInfo->dwUsedSize = pCallInfo->dwNeededSize; // validate string size if (dwCalleeNameSize > 0) { if( m_pCalleeAliasNames -> pItems[0].wType == e164_chosen ) { // callee number was specified pCallInfo->dwCalledIDFlags = LINECALLPARTYID_ADDRESS; // determine size and offset for callee number pCallInfo->dwCalledIDSize = dwCalleeNameSize; pCallInfo->dwCalledIDOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwCalledIDOffset), (LPBYTE)m_pCalleeAliasNames -> pItems[0].pData, pCallInfo->dwCalledIDSize ); } else { // callee name was specified pCallInfo->dwCalledIDFlags = LINECALLPARTYID_NAME; // determine size and offset for callee name pCallInfo->dwCalledIDNameSize = dwCalleeNameSize; pCallInfo->dwCalledIDNameOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwCalledIDNameOffset), (LPBYTE)m_pCalleeAliasNames -> pItems[0].pData, pCallInfo->dwCalledIDNameSize ); } // adjust offset to include string dwNextOffset += dwCalleeNameSize; H323DBG(( DEBUG_LEVEL_TRACE, "callee name: %S.", m_pCalleeAliasNames -> pItems[0].pData )); } // validate string size if (dwCallerNameSize > 0) { // caller name was specified pCallInfo->dwCallerIDFlags = LINECALLPARTYID_NAME; // determine size and offset for caller name pCallInfo->dwCallerIDNameSize = dwCallerNameSize; pCallInfo->dwCallerIDNameOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwCallerIDNameOffset), (LPBYTE)m_pCallerAliasNames -> pItems[0].pData, pCallInfo->dwCallerIDNameSize ); //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); // adjust offset to include string dwNextOffset += dwCallerNameSize; H323DBG(( DEBUG_LEVEL_TRACE, "caller name: %S.", m_pCallerAliasNames -> pItems[0].pData )); } if( dwCallerAddressSize > 0 ) { // caller number was specified pCallInfo->dwCallerIDFlags |= LINECALLPARTYID_ADDRESS; // determine size and offset for caller number pCallInfo->dwCallerIDSize = dwCallerAddressSize; pCallInfo->dwCallerIDOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwCallerIDOffset), (LPBYTE)wszIPAddress, pCallInfo->dwCallerIDSize ); // adjust offset to include string dwNextOffset += dwCallerAddressSize; } // validate buffer if (dwU2USize > 0) { // determine size and offset of info pCallInfo->dwUserUserInfoSize = dwU2USize; pCallInfo->dwUserUserInfoOffset = dwNextOffset; // copy user user info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwUserUserInfoOffset), (LPBYTE)pU2U, pCallInfo->dwUserUserInfoSize ); // adjust offset to include string dwNextOffset += pCallInfo->dwUserUserInfoSize; } if( dwDivertingNameSize > 0 ) { // caller name was specified pCallInfo->dwRedirectingIDFlags = LINECALLPARTYID_NAME; // determine size and offset for caller name pCallInfo->dwRedirectingIDNameSize = dwDivertingNameSize; pCallInfo->dwRedirectingIDNameOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwRedirectingIDNameOffset), (LPBYTE)(m_pCallReroutingInfo->divertingNrAlias->pItems[0].pData), pCallInfo->dwRedirectingIDNameSize ); // adjust offset to include string dwNextOffset += dwDivertingNameSize; H323DBG(( DEBUG_LEVEL_TRACE, "diverting name: %S.", m_pCallReroutingInfo->divertingNrAlias->pItems[0].pData )); } if( dwDiversionNameSize > 0 ) { // caller name was specified pCallInfo->dwRedirectionIDFlags = LINECALLPARTYID_NAME; // determine size and offset for caller name pCallInfo->dwRedirectionIDNameSize = dwDiversionNameSize; pCallInfo->dwRedirectionIDNameOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwRedirectionIDNameOffset), (LPBYTE)(m_pCallReroutingInfo->diversionNrAlias->pItems[0].pData), pCallInfo->dwRedirectionIDNameSize ); // adjust offset to include string dwNextOffset += dwDiversionNameSize; H323DBG(( DEBUG_LEVEL_TRACE, "redirection name: %S.", m_pCallReroutingInfo->diversionNrAlias->pItems[0].pData )); } if( dwDivertedToNameSize > 0 ) { pCallInfo->dwRedirectionIDFlags = LINECALLPARTYID_NAME; // determine size and offset for caller name pCallInfo->dwRedirectionIDNameSize = dwDivertedToNameSize; pCallInfo->dwRedirectionIDNameOffset = dwNextOffset; // copy call info after fixed portion CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo->dwRedirectionIDNameOffset), (LPBYTE)(m_pCallReroutingInfo->divertedToNrAlias->pItems[0].pData), pCallInfo->dwRedirectionIDNameSize ); // adjust offset to include string dwNextOffset += pCallInfo->dwRedirectionIDNameSize; // adjust offset to include string dwNextOffset += dwDivertedToNameSize; H323DBG(( DEBUG_LEVEL_TRACE, "redirection name: %S.", m_pCallReroutingInfo->divertedToNrAlias->pItems[0].pData )); } //pass on the call data if( dwCallDataSize > 0 ) { pCallInfo -> dwCallDataSize = dwCallDataSize; pCallInfo -> dwCallDataOffset = dwNextOffset; CopyMemory( (PVOID)((LPBYTE)pCallInfo + pCallInfo -> dwCallDataOffset), (LPBYTE)m_CallData.pOctetString, pCallInfo -> dwCallDataSize ); dwNextOffset += dwCallDataSize; } } else if (pCallInfo->dwTotalSize >= sizeof(LINECALLINFO)) { H323DBG(( DEBUG_LEVEL_WARNING, "linecallinfo structure too small for strings." )); // structure only contains fixed portion pCallInfo->dwUsedSize = sizeof(LINECALLINFO); } else { H323DBG(( DEBUG_LEVEL_ERROR, "linecallinfo structure too small." )); // structure is too small return LINEERR_STRUCTURETOOSMALL; } // initialize call line device and address info pCallInfo->dwLineDeviceID = g_pH323Line->GetDeviceID(); pCallInfo->dwAddressID = 0; // initialize variable call parameters pCallInfo->dwOrigin = m_dwOrigin; pCallInfo->dwMediaMode = m_dwIncomingModes | m_dwOutgoingModes; if( m_dwCallType & CALLTYPE_DIVERTEDDEST ) { if(m_pCallReroutingInfo->diversionReason==DiversionReason_cfu) { pCallInfo->dwReason = LINECALLREASON_FWDUNCOND; } else if(m_pCallReroutingInfo->diversionReason==DiversionReason_cfnr) { pCallInfo->dwReason = LINECALLREASON_FWDNOANSWER; } else { pCallInfo->dwReason = LINECALLREASON_FWDBUSY; } } if( m_dwCallType & CALLTYPE_TRANSFEREDDEST ) { pCallInfo->dwReason = LINECALLREASON_TRANSFER; } else { pCallInfo->dwReason = LINECALLREASON_DIRECT; } pCallInfo->dwCallStates = (m_dwOrigin==LINECALLORIGIN_INBOUND) ? H323_CALL_INBOUNDSTATES : H323_CALL_OUTBOUNDSTATES ; // initialize constant call parameters pCallInfo->dwBearerMode = H323_LINE_BEARERMODES; pCallInfo->dwRate = H323_LINE_MAXRATE; // initialize unsupported call capabilities pCallInfo->dwConnectedIDFlags = LINECALLPARTYID_UNAVAIL; //pass on the dwAppSpecific info pCallInfo -> dwAppSpecific = m_dwAppSpecific; H323DBG(( DEBUG_LEVEL_ERROR, "CopyCallInfo exited:%p.",this )); return retVal; } //!!always called in lock BOOL CH323Call::HandleReadyToInitiate( IN PTspMspMessage pMessage ) { Q931_SETUP_ASN setupASN; WORD wCount; DWORD dwAPDUType = 0; H323DBG(( DEBUG_LEVEL_ERROR, "HandleReadyToInitiate entered:%p.", this )); //set the additional callee addresses and callee aliases //see if there is a fast-connect proposal if( pMessage->dwEncodedASNSize != 0 ) { if( !ParseSetupASN( pMessage ->pEncodedASNBuf, pMessage->dwEncodedASNSize, &setupASN, &dwAPDUType )) { goto cleanup; } if( setupASN.fFastStartPresent ) { _ASSERTE( !m_pFastStart ); m_pFastStart = setupASN.pFastStart; setupASN.pFastStart = NULL; m_dwFastStart = FAST_START_SELF_AVAIL; } else { m_dwFastStart = FAST_START_NOTAVAIL; } if( setupASN.pCallerAliasList && !RasIsRegistered() ) { //_ASSERTE(0); if( m_pCallerAliasNames == NULL ) { m_pCallerAliasNames = setupASN.pCallerAliasList; //dont release this alias list setupASN.pCallerAliasList = NULL; } else { wCount = m_pCallerAliasNames->wCount + setupASN.pCallerAliasList->wCount; PH323_ALIASITEM tempPtr = NULL; tempPtr = (PH323_ALIASITEM)realloc( (PVOID)setupASN.pCallerAliasList->pItems, wCount * sizeof(H323_ALIASITEM) ); if( tempPtr == NULL ) { //restore the old pointer in case enough memory was not //available to expand the memory block } else { setupASN.pCallerAliasList->pItems = tempPtr; CopyMemory( (PVOID)&(setupASN.pCallerAliasList->pItems[setupASN.pCallerAliasList->wCount]), (PVOID)m_pCallerAliasNames->pItems, m_pCallerAliasNames->wCount * sizeof(H323_ALIASITEM) ); setupASN.pCallerAliasList->wCount = wCount; delete m_pCallerAliasNames->pItems; delete m_pCallerAliasNames; m_pCallerAliasNames = setupASN.pCallerAliasList; setupASN.pCallerAliasList = NULL; } } } //add the callee aliases sent by the MSP if( setupASN.pCalleeAliasList != NULL ) { //_ASSERTE(0); if( m_pCalleeAliasNames == NULL ) { m_pCalleeAliasNames = setupASN.pCalleeAliasList; //dont release this alias list setupASN.pCalleeAliasList = NULL; } else { wCount = m_pCalleeAliasNames->wCount + setupASN.pCalleeAliasList->wCount; PH323_ALIASITEM tempPtr = NULL; tempPtr = (PH323_ALIASITEM)realloc( (PVOID)m_pCalleeAliasNames->pItems, wCount * sizeof(H323_ALIASITEM) ); if( tempPtr == NULL ) { //restore the old pointer in case enough memory was not //available to expand the memory block goto cleanup; } m_pCalleeAliasNames->pItems = tempPtr; CopyMemory( (PVOID)&(m_pCalleeAliasNames->pItems[m_pCalleeAliasNames->wCount]), (PVOID)setupASN.pCalleeAliasList->pItems, setupASN.pCalleeAliasList->wCount * sizeof(H323_ALIASITEM) ); m_pCalleeAliasNames->wCount = wCount; delete setupASN.pCalleeAliasList->pItems; delete setupASN.pCalleeAliasList; setupASN.pCalleeAliasList = NULL; } } FreeSetupASN( &setupASN ); } else { m_dwFastStart = FAST_START_NOTAVAIL; } //send the setup message if( !SendSetupMessage() ) { DropCall( 0 ); } H323DBG(( DEBUG_LEVEL_ERROR, "HandleReadyToInitiate exited:%p.", this )); return TRUE; cleanup: CloseCall( 0 ); FreeSetupASN( &setupASN ); return FALSE; } //!!always called in lock BOOL CH323Call::HandleProceedWithAnswer( IN PTspMspMessage pMessage ) { Q931_CALL_PROCEEDING_ASN proceedingASN; DWORD dwAPDUType = 0; PH323_ALIASITEM pwszDivertedToAlias = NULL; WCHAR *pwszAliasName = NULL; WORD wAliasLength = 0; H323DBG(( DEBUG_LEVEL_TRACE, "HandleProceedWithAnswer entered:%p.", this )); if( m_dwCallType & CALLTYPE_DIVERTED_SERVED ) { H323DBG(( DEBUG_LEVEL_TRACE, "Call already diverted. ignore the message:%p.", this )); return TRUE; } //see if there is a fast-connect proposal if( pMessage->dwEncodedASNSize != 0 ) { if( !ParseProceedingASN(pMessage ->pEncodedASNBuf, pMessage->dwEncodedASNSize, &proceedingASN, &dwAPDUType ) ) { goto cleanup; } if( proceedingASN.fH245AddrPresent ) { m_selfH245Addr = proceedingASN.h245Addr; } if( proceedingASN.fFastStartPresent && (m_dwFastStart!=FAST_START_NOTAVAIL) ) { _ASSERTE( m_pFastStart == NULL ); m_pFastStart = proceedingASN.pFastStart; m_dwFastStart = FAST_START_AVAIL; //we keep a reference to the fast start list so don't release it proceedingASN.pFastStart = NULL; proceedingASN.fFastStartPresent = FALSE; } /*else { m_dwFastStart = FAST_START_NOTAVAIL; }*/ FreeProceedingASN( &proceedingASN ); } /*else { m_dwFastStart = FAST_START_NOTAVAIL; }*/ //send proceeding message to the peer if(!SendProceeding() ) { goto cleanup; } //send alerting message to the peer if( !SendQ931Message(NO_INVOKEID, 0, 0, ALERTINGMESSAGETYPE, NO_H450_APDU) ) { goto cleanup; } m_dwStateMachine = Q931_ALERT_SENT; //for TRANSFEREDDEST call directly accept the call wihtout the user //answering the call if( (m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall ) { AcceptCall(); } if( m_pCallerAliasNames && (m_pCallerAliasNames -> wCount > 0) ) { pwszAliasName = m_pCallerAliasNames->pItems[0].pData; wAliasLength = (m_pCallerAliasNames->pItems[0].wDataLength+1) * sizeof(WCHAR); //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } pwszDivertedToAlias = g_pH323Line->CallToBeDiverted( pwszAliasName, wAliasLength, LINEFORWARDMODE_NOANSW | LINEFORWARDMODE_NOANSWSPECIFIC | LINEFORWARDMODE_BUSYNA | LINEFORWARDMODE_BUSYNASPECIFIC ); //if call is to be diverted for no answer, start the timer if( pwszDivertedToAlias != NULL ) { if( !StartTimerForCallDiversionOnNA( pwszDivertedToAlias ) ) { goto cleanup; } } H323DBG(( DEBUG_LEVEL_TRACE, "HandleProceedWithAnswer exited:%p.",this )); return TRUE; cleanup: CloseCall( 0 ); return FALSE; } //!!always called in lock BOOL CH323Call::HandleReadyToAnswer( IN PTspMspMessage pMessage ) { Q931_CALL_PROCEEDING_ASN proceedingASN; DWORD dwAPDUType = 0; PH323_CALL pConsultCall = NULL; H323DBG(( DEBUG_LEVEL_ERROR, "HandleReadyToAnswer entered:%p.",this )); m_fReadyToAnswer = TRUE; //see if there is a fast-connect proposal if( pMessage->dwEncodedASNSize != 0 ) { if( !ParseProceedingASN(pMessage ->pEncodedASNBuf, pMessage->dwEncodedASNSize, &proceedingASN, &dwAPDUType) ) { goto cleanup; } if( proceedingASN.fH245AddrPresent ) { m_selfH245Addr = proceedingASN.h245Addr; } if( proceedingASN.fFastStartPresent && (m_dwFastStart!=FAST_START_NOTAVAIL) ) { _ASSERTE( m_pFastStart == NULL ); m_pFastStart = proceedingASN.pFastStart; m_dwFastStart = FAST_START_AVAIL; //we keep a reference to the fast start list so don't release it proceedingASN.pFastStart = NULL; proceedingASN.fFastStartPresent = FALSE; } else { m_dwFastStart = FAST_START_NOTAVAIL; } FreeProceedingASN( &proceedingASN ); } else { m_dwFastStart = FAST_START_NOTAVAIL; } if( m_fCallAccepted ) { // validate status if( !AcceptH323Call() ) { H323DBG(( DEBUG_LEVEL_ERROR, "error answering call 0x%08lx.", this )); // failure goto cleanup; } //lock the primary call after replacement call to avoid deadlock if( (m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall ) { QueueSuppServiceWorkItem( SWAP_REPLACEMENT_CALL, m_hdCall, (ULONG_PTR)m_hdRelatedCall ); } else { //send MSP start H245 SendMSPStartH245( NULL, NULL ); //tell MSP about connect state SendMSPMessage( SP_MSG_ConnectComplete, 0, 0, NULL ); } //change call state to accepted from offering ChangeCallState( LINECALLSTATE_CONNECTED, 0 ); } H323DBG(( DEBUG_LEVEL_ERROR, "HandleReadyToAnswer exited:%p.",this )); return TRUE; cleanup: CloseCall( 0 ); return FALSE; } //!!This function must be always called in a lock. The calling function should //not unlock the call object as this function itself unlocks the call object BOOL CH323Call::HandleMSPMessage( IN PTspMspMessage pMessage, IN HDRVMSPLINE hdMSPLine, IN HTAPIMSPLINE htMSPLine ) { BOOL fResult = TRUE; PH323_CALL pCall = NULL; ASN1octetstring_t pH245PDU; H323DBG(( DEBUG_LEVEL_TRACE, "HandleMSPMessage entered:%p.",this )); H323DBG(( DEBUG_LEVEL_TRACE, "MSP message:%s recvd.", H323TSPMessageToString(pMessage->MessageType) )); switch( pMessage -> MessageType ) { case SP_MSG_ReadyToInitiate: // The Q.931 connection should be in the connected state by now if( pMessage -> MsgBody.ReadyToInitiateMessage.hMSPReplacementCall != NULL ) { //unlock the primary call before locking the related call Unlock(); pCall=g_pH323Line -> FindH323CallAndLock(m_hdRelatedCall); if( pCall == NULL ) { //transfered call is not around so close the primary call CloseCall( 0 ); return TRUE; } fResult = pCall -> HandleReadyToInitiate( pMessage ); pCall -> Unlock(); } else { m_hdMSPLine = hdMSPLine; m_htMSPLine = htMSPLine; fResult = HandleReadyToInitiate( pMessage ); Unlock(); } break; case SP_MSG_ProceedWithAnswer: if( pMessage -> MsgBody.ProceedWithAnswerMessage.hMSPReplacementCall != NULL ) { //unlock the primary call before locking the related call Unlock(); pCall=g_pH323Line -> FindH323CallAndLock(m_hdRelatedCall); if( pCall == NULL ) { //transfered call is not around so close the primary call CloseCall( 0 ); return FALSE; } fResult = pCall -> HandleProceedWithAnswer( pMessage ); pCall -> Unlock(); } else { m_hdMSPLine = hdMSPLine; m_htMSPLine = htMSPLine; fResult = HandleProceedWithAnswer( pMessage ); Unlock(); } break; case SP_MSG_ReadyToAnswer: if( pMessage -> MsgBody.ReadyToAnswerMessage.hMSPReplacementCall != NULL ) { //unlock the primary call before locking the related call Unlock(); pCall=g_pH323Line -> FindH323CallAndLock(m_hdRelatedCall); if( pCall== NULL ) { //transfered call is not around so close the primary call CloseCall( 0 ); return FALSE; } fResult = pCall -> HandleReadyToAnswer( pMessage ); pCall -> Unlock(); } else { //decode call_proceding message and extract local fast //start inforamtion and local H245 address fResult = HandleReadyToAnswer( pMessage ); Unlock(); } break; case SP_MSG_ReleaseCall: //shutdown the H323 call CloseCall( LINEDISCONNECTMODE_CANCELLED ); Unlock(); break; case SP_MSG_H245Terminated: //shutdown the H323 call CloseCall( LINEDISCONNECTMODE_NORMAL ); Unlock(); break; case SP_MSG_SendDTMFDigits: if( m_fMonitoringDigits == TRUE ) { WCHAR * pwch = pMessage->pWideChars; H323DBG(( DEBUG_LEVEL_VERBOSE, "dtmf digits recvd:%S.", pwch)); // process each digit WORD indexI=0; while( indexI < pMessage->MsgBody.SendDTMFDigitsMessage.wNumDigits ) { // signal incoming PostLineEvent( LINE_MONITORDIGITS, (DWORD_PTR)*pwch, LINEDIGITMODE_DTMF, GetTickCount() ); ++pwch; indexI++; } } Unlock(); break; case SP_MSG_LegacyDefaultAlias: if( pMessage -> MsgBody.LegacyDefaultAliasMessage.wNumChars > 0 ) { if( !RasIsRegistered() ) { _ASSERTE( m_pwszDisplay == NULL ); m_pwszDisplay = new WCHAR[ pMessage -> MsgBody.LegacyDefaultAliasMessage.wNumChars ]; if( m_pwszDisplay != NULL ) { CopyMemory( (PVOID)m_pwszDisplay, pMessage->pWideChars, sizeof(WCHAR) * pMessage -> MsgBody.LegacyDefaultAliasMessage.wNumChars ); } } } Unlock(); break; case SP_MSG_H245PDU: if( (pMessage ->pEncodedASNBuf) && (pMessage->dwEncodedASNSize != 0) ) { pH245PDU.value = pMessage ->pEncodedASNBuf; pH245PDU.length = pMessage->dwEncodedASNSize; fResult = SendQ931Message( NO_INVOKEID, 0, (ULONG_PTR)&pH245PDU, FACILITYMESSAGETYPE, NO_H450_APDU ); } Unlock(); break; case SP_MSG_RASRegistrationEvent: default: _ASSERTE(0); Unlock(); break; } H323DBG(( DEBUG_LEVEL_ERROR, "HandleMSPMessage exited:%p.",this )); return fResult; } //!!always called in a lock void CH323Call::SendMSPMessage( IN TspMspMessageType messageType, IN BYTE* pbEncodedBuf, IN DWORD dwLength, IN HDRVCALL hReplacementCall ) { TspMspMessageEx messageEx; HTAPIMSPLINE hMSP = MSP_HANDLE_UNKNOWN; int iError = 0; int iLen = sizeof(SOCKADDR_IN); SOCKADDR_IN* psaLocalQ931Addr = NULL; H323DBG(( DEBUG_LEVEL_ERROR, "SendMSPMessage:%s entered:%p.", H323TSPMessageToString(messageType), this )); messageEx.message.MessageType = messageType; switch( messageType ) { case SP_MSG_InitiateCall: messageEx.message.MsgBody.InitiateCallMessage.hTSPReplacementCall = (HANDLE)hReplacementCall; messageEx.message.MsgBody.InitiateCallMessage.hTSPConferenceCall = m_hdConf; psaLocalQ931Addr = &messageEx.message.MsgBody.InitiateCallMessage.saLocalQ931Addr; ZeroMemory( (PVOID)psaLocalQ931Addr, sizeof(SOCKADDR_IN) ); *psaLocalQ931Addr = m_LocalAddr; psaLocalQ931Addr->sin_family = AF_INET; break; case SP_MSG_PrepareToAnswer: if( (dwLength<=0) || (dwLength > sizeof(messageEx.pEncodedASN)) || (!pbEncodedBuf) ) { CloseCall( 0 ); return; } messageEx.message.MsgBody.PrepareToAnswerMessage.hReplacementCall = (HANDLE)hReplacementCall; psaLocalQ931Addr = &messageEx.message.MsgBody.PrepareToAnswerMessage.saLocalQ931Addr; ZeroMemory( (PVOID)psaLocalQ931Addr, sizeof(SOCKADDR_IN) ); *psaLocalQ931Addr = m_LocalAddr; psaLocalQ931Addr->sin_family = AF_INET; //send the received Setup message. This should have the information //about m_pPeerFastStart param as wel CopyMemory( (PVOID)messageEx.message.pEncodedASNBuf, (PVOID)pbEncodedBuf, dwLength ); break; case SP_MSG_SendDTMFDigits: if( (dwLength<=0) || (dwLength > sizeof(messageEx.pEncodedASN)) || (!pbEncodedBuf) ) { CloseCall( 0 ); return; } hMSP = m_htMSPLine; messageEx.message.MsgBody.SendDTMFDigitsMessage.wNumDigits = (WORD)dwLength; dwLength = (dwLength+1) * sizeof(WCHAR); CopyMemory( (PVOID)messageEx.message.pEncodedASNBuf, (PVOID)pbEncodedBuf, dwLength ); break; case SP_MSG_ConnectComplete: case SP_MSG_CallShutdown: //dont set anything hMSP = m_htMSPLine; break; case SP_MSG_H245PDU: case SP_MSG_AnswerCall: hMSP = m_htMSPLine; break; case SP_MSG_Hold: hMSP = m_htMSPLine; messageEx.message.MsgBody.HoldMessage.fHold = (BOOL)dwLength; dwLength = 0; break; } messageEx.message.dwMessageSize = sizeof(TspMspMessage) + dwLength - ((dwLength)?sizeof(WORD):0); if( messageType == SP_MSG_SendDTMFDigits ) { messageEx.message.dwEncodedASNSize = 0; } else { messageEx.message.dwEncodedASNSize = dwLength; } //send msp message PostLineEvent ( LINE_SENDMSPDATA, (DWORD_PTR)hMSP, //This handle should be NULL when htCall param is a valid value (DWORD_PTR)&(messageEx.message), messageEx.message.dwMessageSize); H323DBG(( DEBUG_LEVEL_ERROR, "SendMSPMessage exited:%p.",this )); return; } //always called in lock void CH323Call::SendMSPStartH245( PH323_ADDR pPeerH245Addr, PH323_FASTSTART pPeerFastStart ) { TspMspMessageEx messageEx; WORD wEncodedLength; BYTE* pEncodedASNBuffer; H323DBG(( DEBUG_LEVEL_ERROR, "SendMSPStartH245 entered:%p.", this )); wEncodedLength = 0; messageEx.message.MessageType = SP_MSG_StartH245; messageEx.message.MsgBody.StartH245Message.hMSPReplaceCall = NULL; messageEx.message.MsgBody.StartH245Message.hTSPReplacementCall = (HANDLE)pPeerH245Addr; ZeroMemory( messageEx.message.MsgBody.StartH245Message.ConferenceID, sizeof(GUID) ); messageEx.message.MsgBody.StartH245Message.fH245TunnelCapability = FALSE; messageEx.message.MsgBody.StartH245Message.fH245AddressPresent = FALSE; memset( (PVOID)&messageEx.message.MsgBody.StartH245Message.saH245Addr, 0, sizeof(SOCKADDR_IN) ); //for outgoing call send the fast start proposal. if( (m_dwOrigin==LINECALLORIGIN_OUTBOUND) || pPeerH245Addr ) { if( pPeerH245Addr == NULL ) { pPeerFastStart = m_pPeerFastStart; } if( pPeerFastStart != NULL ) { if( !EncodeFastStartProposal( pPeerFastStart, &pEncodedASNBuffer, &wEncodedLength ) ) { CloseCall( 0 ); return; } CopyMemory( (PVOID)messageEx.message.pEncodedASNBuf, (PVOID)pEncodedASNBuffer, wEncodedLength ); ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedASNBuffer ); } } //If outgoing call send peer's H245 address if( (m_dwOrigin == LINECALLORIGIN_OUTBOUND) || pPeerH245Addr ) { if( pPeerH245Addr == NULL ) { pPeerH245Addr = &m_peerH245Addr; } messageEx.message.MsgBody.StartH245Message.fH245AddressPresent = FALSE; if( pPeerH245Addr->Addr.IP_Binary.dwAddr != 0 ) { messageEx.message.MsgBody.StartH245Message.saH245Addr.sin_family = AF_INET; messageEx.message.MsgBody.StartH245Message.saH245Addr.sin_port = htons(pPeerH245Addr->Addr.IP_Binary.wPort); messageEx.message.MsgBody.StartH245Message.saH245Addr.sin_addr.s_addr = htonl(pPeerH245Addr->Addr.IP_Binary.dwAddr); messageEx.message.MsgBody.StartH245Message.fH245AddressPresent = TRUE; } } //set the Q931 address ZeroMemory( (PVOID)&messageEx.message.MsgBody.StartH245Message.saQ931Addr, sizeof(SOCKADDR_IN) ); messageEx.message.MsgBody.StartH245Message.saQ931Addr.sin_family = AF_INET; messageEx.message.MsgBody.StartH245Message.saQ931Addr.sin_port = htons( m_CalleeAddr.Addr.IP_Binary.wPort ); messageEx.message.MsgBody.StartH245Message.saQ931Addr.sin_addr.s_addr = htonl( m_CalleeAddr.Addr.IP_Binary.dwAddr ); messageEx.message.MsgBody.StartH245Message.fH245TunnelCapability = (m_fh245Tunneling & REMOTE_H245_TUNNELING) && (m_fh245Tunneling & LOCAL_H245_TUNNELING); messageEx.message.dwMessageSize = sizeof(messageEx.message) + wEncodedLength - ((wEncodedLength)?1:0); messageEx.message.dwEncodedASNSize = wEncodedLength; // send msp message PostLineEvent ( LINE_SENDMSPDATA, //this handle should be NULL when htCall is a valid handle. (DWORD_PTR)NULL, (DWORD_PTR)&(messageEx.message), messageEx.message.dwMessageSize); m_dwFlags |= H245_START_MSG_SENT; H323DBG(( DEBUG_LEVEL_ERROR, "SendMSPStartH245 exited:%p.",this )); return; } //always called in lock BOOL CH323Call::AddU2U( IN DWORD dwDirection, IN DWORD dwDataSize, IN PBYTE pData ) /*++ Routine Description: Create user user structure and adds to list. Arguments: pLftHead - Pointer to list in which to add user user info. dwDataSize - Size of buffer pointed to by pData. pData - Pointer to user user info. Return Values: Returns true if successful. --*/ { PLIST_ENTRY pListHead = NULL; PUserToUserLE pU2ULE; H323DBG(( DEBUG_LEVEL_ERROR, "AddU2U entered:%p.",this )); if( dwDirection == U2U_OUTBOUND ) { pListHead = &m_OutgoingU2U; } else { pListHead = &m_IncomingU2U; } // validate data buffer pointer and size if( (pData != NULL) && (dwDataSize > 0) ) { // allocate memory for user user info pU2ULE = new UserToUserLE; // validate pointer if (pU2ULE == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate user user info." )); // failure return FALSE; } // aim pointer at the end of the buffer by default pU2ULE->pU2U = new BYTE[ dwDataSize ]; // validate pointer if (pU2ULE->pU2U == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate user user info." )); delete pU2ULE; // failure return FALSE; } pU2ULE->dwU2USize = dwDataSize; // transfer user user info into list entry CopyMemory( (PVOID)pU2ULE->pU2U, (PVOID)pData, pU2ULE->dwU2USize); // add list entry to back of list InsertTailList(pListHead, &pU2ULE->Link); H323DBG(( DEBUG_LEVEL_VERBOSE, "added user user info 0x%08lx (%d bytes).", pU2ULE->pU2U, pU2ULE->dwU2USize )); } H323DBG(( DEBUG_LEVEL_ERROR, "AddU2U exited:%p.",this )); // success return TRUE; } /*++ Routine Description: Create user user structure and adds to list. !!always called in lock. Arguments: pLftHead - Pointer to list in which to add user user info. dwDataSize - Size of buffer pointed to by pData. pData - Pointer to user user info. Return Values: Returns true if successful. --*/ BOOL CH323Call::AddU2UNoAlloc( IN DWORD dwDirection, IN DWORD dwDataSize, IN PBYTE pData ) { PLIST_ENTRY pListHead = NULL; PUserToUserLE pU2ULE; H323DBG(( DEBUG_LEVEL_ERROR, "AddU2U entered:%p.",this )); if( dwDirection == U2U_OUTBOUND ) { pListHead = &m_OutgoingU2U; } else { pListHead = &m_IncomingU2U; } // validate data buffer pointer and size if( (pData != NULL) && (dwDataSize > 0) ) { // allocate memory for user user info pU2ULE = new UserToUserLE; // validate pointer if (pU2ULE == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate user user info." )); // failure return FALSE; } // aim pointer at the end of the buffer by default pU2ULE->pU2U = pData; pU2ULE->dwU2USize = dwDataSize; // add list entry to back of list InsertTailList(pListHead, &pU2ULE->Link); H323DBG(( DEBUG_LEVEL_VERBOSE, "added user user info 0x%08lx (%d bytes).", pU2ULE->pU2U, pU2ULE->dwU2USize )); } H323DBG(( DEBUG_LEVEL_ERROR, "AddU2U exited:%p.",this )); // success return TRUE; } //!!must be always called in a lock. BOOL CH323Call::RemoveU2U( IN DWORD dwDirection, IN PUserToUserLE * ppU2ULE ) /*++ Routine Description: Removes user user info structure from list. Arguments: pListHead - Pointer to list in which to remove user user info. ppU2ULE - Pointer to pointer to list entry. Return Values: Returns true if successful. --*/ { PLIST_ENTRY pListHead = NULL; PLIST_ENTRY pLE; H323DBG(( DEBUG_LEVEL_ERROR, "RemoveU2U entered:%p.",this )); if( dwDirection == U2U_OUTBOUND ) { pListHead = &m_OutgoingU2U; } else { pListHead = &m_IncomingU2U; } // process list until empty if( IsListEmpty(pListHead) == FALSE ) { // retrieve first entry pLE = RemoveHeadList(pListHead); // convert list entry to structure pointer *ppU2ULE = CONTAINING_RECORD(pLE, UserToUserLE, Link); H323DBG(( DEBUG_LEVEL_VERBOSE, "removed user user info 0x%08lx (%d bytes).", (*ppU2ULE)->pU2U, (*ppU2ULE)->dwU2USize )); H323DBG(( DEBUG_LEVEL_ERROR, "RemoveU2U exited:%p.",this )); // success return TRUE; } // failure return FALSE; } BOOL CH323Call::FreeU2U( IN DWORD dwDirection ) /*++ Routine Description: Releases memory for user user list. !!must be always called in a lock. Arguments pListHead - Pointer to list in which to free user user info. Return Values: Returns true if successful. --*/ { PLIST_ENTRY pLE; PUserToUserLE pU2ULE; PLIST_ENTRY pListHead = NULL; H323DBG(( DEBUG_LEVEL_ERROR, "FreeU2U entered:%p.",this )); if( dwDirection == U2U_OUTBOUND ) { pListHead = &m_OutgoingU2U; } else { pListHead = &m_IncomingU2U; } // process list until empty while( IsListEmpty(pListHead) == FALSE ) { // retrieve first entry pLE = RemoveHeadList(pListHead); // convert list entry to structure pointer pU2ULE = CONTAINING_RECORD(pLE, UserToUserLE, Link); // release memory if( pU2ULE ) { delete pU2ULE; pU2ULE = NULL; } } H323DBG(( DEBUG_LEVEL_ERROR, "FreeU2U exited:%p.",this )); // success return TRUE; } /*++ Routine Description: Resets call object to original state for re-use. Arguments: Return Values: Returns true if successful. --*/ void CH323Call::Shutdown( OUT BOOL * fDelete ) { H323DBG(( DEBUG_LEVEL_ERROR, "Shutdown entered:%p.",this )); if( !(m_dwFlags & CALLOBJECT_INITIALIZED) ) { return; } //acquire the lock on call table before acquiring the lock on call object g_pH323Line -> LockCallTable(); Lock(); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { Unlock(); g_pH323Line -> UnlockCallTable(); return; } // reset tapi info m_dwCallState = LINECALLSTATE_UNKNOWN; m_dwCallStateMode = 0; m_dwOrigin = LINECALLORIGIN_UNKNOWN; m_dwAddressType = 0; m_dwIncomingModes = 0; m_dwOutgoingModes = 0; m_dwRequestedModes = 0; m_fMonitoringDigits = FALSE; // reset tapi handles m_htCall = (HTAPICALL)NULL; // reset addresses memset( (PVOID)&m_CalleeAddr,0,sizeof(H323_ADDR)); memset( (PVOID)&m_CallerAddr,0,sizeof(H323_ADDR)); H323DBG(( DEBUG_LEVEL_ERROR, "deleting calleealias:%p.",this )); FreeAliasNames( m_pCalleeAliasNames ); m_pCalleeAliasNames = NULL; if( m_pCallerAliasNames != NULL ) { //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); FreeAliasNames( m_pCallerAliasNames ); m_pCallerAliasNames = NULL; } //reset non standard data memset( (PVOID)&m_NonStandardData, 0, sizeof(H323NonStandardData) ); // release user user information FreeU2U( U2U_OUTBOUND ); FreeU2U( U2U_INBOUND ); //shutdown the Q931 call if not shutdown yet if( m_hSetupSentTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hSetupSentTimer, NULL ); m_hSetupSentTimer = NULL; } if( m_hCallEstablishmentTimer ) { DeleteTimerQueueTimer(H323TimerQueue, m_hCallEstablishmentTimer, NULL); m_hCallEstablishmentTimer = NULL; } if( m_hCallDivertOnNATimer ) { DeleteTimerQueueTimer(H323TimerQueue, m_hCallDivertOnNATimer, NULL); m_hCallDivertOnNATimer = NULL; } *fDelete = FALSE; if( m_IoRefCount == 0 ) { *fDelete = TRUE; } m_dwStateMachine = Q931_CALL_STATE_NONE; if( m_callSocket != INVALID_SOCKET ) { if(shutdown( m_callSocket, SD_BOTH ) == SOCKET_ERROR) { H323DBG((DEBUG_LEVEL_TRACE, "couldn't shutdown the socket:%d, %p.", WSAGetLastError(), this )); } closesocket( m_callSocket ); m_callSocket = INVALID_SOCKET; } m_pwszDisplay = NULL; FreeVendorInfo( &m_peerVendorInfo ); if( m_peerNonStandardData.sData.pOctetString ) { H323DBG(( DEBUG_LEVEL_ERROR, "deleting nonstd:%p.",this )); delete m_peerNonStandardData.sData.pOctetString; m_peerNonStandardData.sData.pOctetString = NULL; } H323DBG(( DEBUG_LEVEL_ERROR, "deleting xtraalias:%p.",this )); FreeAliasNames( m_pPeerExtraAliasNames ); m_pPeerExtraAliasNames = NULL; H323DBG(( DEBUG_LEVEL_ERROR, "deleting display:%p.",this )); if( m_pPeerDisplay ) { delete m_pPeerDisplay; m_pPeerDisplay = NULL; } if( m_CallData.pOctetString != NULL ) { delete m_CallData.pOctetString; } H323DBG(( DEBUG_LEVEL_ERROR, "deleting hdconf:%p.",this )); // delete conference if( m_hdConf != NULL ) { g_pH323Line -> GetH323ConfTable() -> Remove( m_hdConf ); delete m_hdConf; m_hdConf = NULL; } H323DBG(( DEBUG_LEVEL_ERROR, "deleting preparetoans:%p.",this )); if( m_prepareToAnswerMsgData.pbBuffer ) { delete m_prepareToAnswerMsgData.pbBuffer; } ZeroMemory( (PVOID)&m_prepareToAnswerMsgData, sizeof(BUFFERDESCR) ); H323DBG(( DEBUG_LEVEL_ERROR, "deleting drq timer:%p.",this )); //ras related data structures if( m_hDRQTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hDRQTimer, NULL ); m_hDRQTimer = NULL; } H323DBG(( DEBUG_LEVEL_ERROR, "deleting arq timer:%p.",this )); if( m_hARQTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hARQTimer, NULL ); m_hARQTimer = NULL; } if( m_pPeerFastStart != NULL ) { FreeFastStart( m_pPeerFastStart ); m_pPeerFastStart = NULL; } if( m_pFastStart != NULL ) { FreeFastStart( m_pFastStart ); m_pFastStart = NULL; } if( m_pARQExpireContext != NULL ) { delete m_pARQExpireContext; m_pARQExpireContext = NULL; } if( m_pDRQExpireContext != NULL ) { delete m_pDRQExpireContext; m_pDRQExpireContext = NULL; } FreeCallForwardData(); g_pH323Line -> RemoveCallFromTable (m_hdCall); m_dwFlags |= CALLOBJECT_SHUTDOWN; Unlock(); g_pH323Line -> UnlockCallTable(); H323DBG(( DEBUG_LEVEL_ERROR, "Shutdown exited:%p.",this )); return; } void CH323Call::FreeCallForwardData() { if( m_pCallReroutingInfo ) { FreeCallReroutingInfo(); } if( m_hCheckRestrictionTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCheckRestrictionTimer, NULL ); m_hCheckRestrictionTimer = NULL; } if( m_hCallReroutingTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCallReroutingTimer, NULL ); m_hCallReroutingTimer = NULL; } if( m_hCTIdentifyTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCTIdentifyTimer, NULL ); m_hCTIdentifyTimer = NULL; } if( m_hCTIdentifyRRTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCTIdentifyRRTimer, NULL ); m_hCTIdentifyRRTimer = NULL; } if( m_hCTInitiateTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCTInitiateTimer, NULL ); m_hCTInitiateTimer = NULL; } if( m_pTransferedToAlias ) { FreeAliasNames( m_pTransferedToAlias ); m_pTransferedToAlias = NULL; } if( m_dwCallType & CALLTYPE_TRANSFERED2_CONSULT ) { g_pH323Line -> RemoveFromCTCallIdentityTable( m_hdCall ); } if( m_H450ASNCoderInfo.pEncInfo ) { TermH450ASNCoder(); } if( m_pCallForwardParams ) { FreeCallForwardParams( m_pCallForwardParams ); m_pCallForwardParams = NULL; } if( m_pForwardAddress ) { FreeForwardAddress( m_pForwardAddress ); m_pForwardAddress = NULL; } } BOOL CH323Call::ResolveCallerAddress(void) /*++ Routine Description: Resolves caller address from callee address. !!must be always called in a lock. Arguments: Return Values: Returns true if successful. --*/ { INT nStatus; SOCKET hCtrlSocket = INVALID_SOCKET; SOCKADDR CalleeSockAddr; SOCKADDR CallerSockAddr; DWORD dwNumBytesReturned = 0; H323DBG(( DEBUG_LEVEL_ERROR, "ResolveCallerAddress entered:%p.",this )); // allocate control socket hCtrlSocket = WSASocket( AF_INET, // af SOCK_DGRAM, // type IPPROTO_IP, // protocol NULL, // lpProtocolInfo 0, // g WSA_FLAG_OVERLAPPED // dwFlags ); // validate control socket if (hCtrlSocket == INVALID_SOCKET) { H323DBG(( DEBUG_LEVEL_ERROR, "error %d creating control socket.", WSAGetLastError() )); // failure return FALSE; } // initialize ioctl parameters memset( (PVOID)&CalleeSockAddr,0,sizeof(SOCKADDR)); memset( (PVOID)&CallerSockAddr,0,sizeof(SOCKADDR)); // initialize address family CalleeSockAddr.sa_family = AF_INET; // transfer callee information ((SOCKADDR_IN*)&CalleeSockAddr)->sin_addr.s_addr = htonl(m_CalleeAddr.Addr.IP_Binary.dwAddr); // query stack nStatus = WSAIoctl( hCtrlSocket, SIO_ROUTING_INTERFACE_QUERY, &CalleeSockAddr, sizeof(SOCKADDR), &CallerSockAddr, sizeof(SOCKADDR), &dwNumBytesReturned, NULL, NULL ); // release handle closesocket(hCtrlSocket); // validate return code if (nStatus == SOCKET_ERROR) { H323DBG(( DEBUG_LEVEL_ERROR, "error 0x%08lx calling SIO_ROUTING_INTERFACE_QUERY.", WSAGetLastError() )); // failure return FALSE; } // save interface address of best route m_CallerAddr.nAddrType = H323_IP_BINARY; m_CallerAddr.Addr.IP_Binary.dwAddr = ntohl(((SOCKADDR_IN*)&CallerSockAddr)->sin_addr.s_addr); m_CallerAddr.Addr.IP_Binary.wPort = LOWORD(g_RegistrySettings.dwQ931ListenPort); m_CallerAddr.bMulticast = IN_MULTICAST(m_CallerAddr.Addr.IP_Binary.dwAddr); H323DBG(( DEBUG_LEVEL_TRACE, "caller address resolved to %s.", H323AddrToString(((SOCKADDR_IN*)&CallerSockAddr)->sin_addr.s_addr) )); H323DBG(( DEBUG_LEVEL_ERROR, "ResolveCallerAddress exited:%p.",this )); // success return TRUE; } BOOL CH323Call::ResolveE164Address( IN LPCWSTR pwszDialableAddr ) /*++ Routine Description: Resolves E.164 address ("4259367111"). !!must be always called in a lock. Arguments: pwszDialableAddr - Specifies a pointer to the dialable address specified by the TAPI application. Return Values: Returns true if successful. --*/ { WCHAR wszAddr[H323_MAXDESTNAMELEN+1]; DWORD dwE164AddrSize; H323DBG(( DEBUG_LEVEL_ERROR, "ResolveE164Address entered:%p.",this )); // make sure pstn gateway has been specified if ((g_RegistrySettings.fIsGatewayEnabled == FALSE) || (g_RegistrySettings.gatewayAddr.nAddrType == 0)) { H323DBG(( DEBUG_LEVEL_ERROR, "pstn gateway not specified." )); // failure return FALSE; } // save gateway address as callee address m_CalleeAddr = g_RegistrySettings.gatewayAddr; dwE164AddrSize = ValidateE164Address( pwszDialableAddr, wszAddr ); if( dwE164AddrSize == 0 ) { H323DBG(( DEBUG_LEVEL_ERROR, "invlid e164 callee alias .")); return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "callee alias resolved to E.164 number." )); H323DBG(( DEBUG_LEVEL_ERROR, "ResolveE164Address exited:%p.",this )); //determine caller address return ResolveCallerAddress(); } DWORD ValidateE164Address( LPCWSTR pwszDialableAddr, WCHAR* wszAddr ) { DWORD dwE164AddrSize = 0; WCHAR * pwszValidE164Chars; WCHAR wszValidE164Chars[] = { H323_ALIAS_H323_PHONE_CHARS L"\0" }; // process until termination char while (*pwszDialableAddr != L'\0') { // reset pointer to valid characters pwszValidE164Chars = wszValidE164Chars; // process until termination char while (*pwszValidE164Chars != L'\0') { // see if valid E.164 character specified if (*pwszDialableAddr == *pwszValidE164Chars) { // save valid character in temp buffer wszAddr[dwE164AddrSize++] = *pwszDialableAddr; break; } // next valid char ++pwszValidE164Chars; } // next input char ++pwszDialableAddr; } // terminate string wszAddr[dwE164AddrSize++] = L'\0'; // validate string if (dwE164AddrSize == 0) { H323DBG(( DEBUG_LEVEL_TRACE, "no valid E.164 characters in string." )); } return dwE164AddrSize; } /*++ Routine Description: Resolves IP address ("172.31.255.231") or DNS entry ("NIKHILB1"). !!must be always called in a lock. Arguments: pszDialableAddr - Specifies a pointer to the dialable address specified by the TAPI application. Return Values: Returns true if successful. --*/ BOOL CH323Call::ResolveIPAddress( IN LPSTR pszDialableAddr ) { DWORD dwIPAddr; struct hostent* pHost; H323DBG(( DEBUG_LEVEL_ERROR, "ResolveIPAddress entered:%p.",this )); // attempt to convert ip address dwIPAddr = inet_addr(pszDialableAddr); // see if address converted if( dwIPAddr == INADDR_NONE ) { // attempt to lookup hostname pHost = gethostbyname(pszDialableAddr); // validate pointer if( pHost != NULL ) { // retrieve host address from structure dwIPAddr = *(unsigned long *)pHost->h_addr; } } // see if address converted if( dwIPAddr == INADDR_NONE ) { H323DBG(( DEBUG_LEVEL_ERROR, "error 0x%08lx resolving IP address.", WSAGetLastError() )); // failure return FALSE; } // save converted address m_CalleeAddr.nAddrType = H323_IP_BINARY; m_CalleeAddr.Addr.IP_Binary.dwAddr = ntohl(dwIPAddr); m_CalleeAddr.Addr.IP_Binary.wPort = LOWORD(g_RegistrySettings.dwQ931ListenPort); m_CalleeAddr.bMulticast = IN_MULTICAST(m_CalleeAddr.Addr.IP_Binary.dwAddr); H323DBG(( DEBUG_LEVEL_TRACE, "callee address resolved to %s:%d.", H323AddrToString(dwIPAddr), m_CalleeAddr.Addr.IP_Binary.wPort )); H323DBG(( DEBUG_LEVEL_ERROR, "ResolveIPAddress exited:%p.",this )); // determine caller address return ResolveCallerAddress(); } BOOL CH323Call::ResolveEmailAddress( IN LPCWSTR pwszDialableAddr, IN LPSTR pszUser, IN LPSTR pszDomain ) /*++ Routine Description: Resolves e-mail address ("nikhilb@microsoft.com"). !!must be always called in a lock. Arguments: pwszDialableAddr - Specifies a pointer to the dialable address specified by the TAPI application. pszUser - Specifies a pointer to the user component of e-mail name. pszDomain - Specified a pointer to the domain component of e-mail name. Return Values: Returns true if successful. --*/ { DWORD dwAddrSize; H323DBG(( DEBUG_LEVEL_ERROR, "ResolveEmailAddress entered:%p.",this )); // size destination address string dwAddrSize = wcslen(pwszDialableAddr) + 1; // attempt to resolve domain locally if( ResolveIPAddress( pszDomain) ) { // success return TRUE; } // make sure proxy has been specified if( (g_RegistrySettings.fIsProxyEnabled == FALSE) || (g_RegistrySettings.proxyAddr.nAddrType == 0) ) { H323DBG(( DEBUG_LEVEL_ERROR, "proxy not specified." )); // failure return FALSE; } // save proxy address as callee address m_CalleeAddr = g_RegistrySettings.proxyAddr; H323DBG(( DEBUG_LEVEL_TRACE, "callee alias resolved to H.323 alias.")); H323DBG(( DEBUG_LEVEL_ERROR, "ResolveEmailAddress exited:%p.",this )); // determine caller address return ResolveCallerAddress(); } /*++ Routine Description: Resolves remote address and determines the correct local address to use in order to reach remote address. !!must be always called in a lock. Arguments: pwszDialableAddr - Specifies a pointer to the dialable address specified by the TAPI application. Return Values: Returns true if successful. --*/ BOOL CH323Call::ResolveAddress( IN LPCWSTR pwszDialableAddr ) { CHAR szDelimiters[] = "@ \t\n"; CHAR szAddr[H323_MAXDESTNAMELEN+1]; LPSTR pszUser = NULL; LPSTR pszDomain = NULL; H323DBG(( DEBUG_LEVEL_ERROR, "ResolveAddress entered:%p.",this )); // validate pointerr if (pwszDialableAddr == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "null destination address." )); // failure return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "resolving %s %S.", H323AddressTypeToString( m_dwAddressType), pwszDialableAddr )); // check whether phone number has been specified if( m_dwAddressType == LINEADDRESSTYPE_PHONENUMBER ) { // need to direct call to pstn gateway return ResolveE164Address( pwszDialableAddr); } // convert address from unicode if (WideCharToMultiByte( CP_ACP, 0, pwszDialableAddr, -1, szAddr, sizeof(szAddr), NULL, NULL ) == 0) { H323DBG(( DEBUG_LEVEL_ERROR, "could not convert address from unicode." )); // failure return FALSE; } // parse user name pszUser = strtok(szAddr, szDelimiters); // parse domain name pszDomain = strtok(NULL, szDelimiters); // validate pointer if (pszUser == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not parse destination address." )); // failure return FALSE; } // validate pointer if (pszDomain == NULL) { // switch pointers pszDomain = pszUser; // re-initialize pszUser = NULL; } H323DBG(( DEBUG_LEVEL_VERBOSE, "resolving user %s domain %s.", pszUser, pszDomain )); H323DBG(( DEBUG_LEVEL_ERROR, "ResolveAddress exited:%p.",this )); // process e-mail and domain names return ResolveEmailAddress( pwszDialableAddr, pszUser, pszDomain ); } BOOL /*++ Routine Description: Validate optional call parameters specified by user. !!no need to call in a lock because not added to the call table yet Arguments: pCallParams - Pointer to specified call parameters to be validated. pwszDialableAddr - Pointer to the dialable address specified by the TAPI application. pdwStatus - Pointer to DWORD containing error code if this routine fails for any reason. Return Values: Returns true if successful. --*/ CH323Call::ValidateCallParams( IN LPLINECALLPARAMS pCallParams, IN LPCWSTR pwszDialableAddr, IN PDWORD pdwStatus ) { DWORD dwMediaModes = H323_LINE_DEFMEDIAMODES; DWORD dwAddrSize; WCHAR wszAddr[H323_MAXDESTNAMELEN+1]; PH323_ALIASNAMES pAliasList; WCHAR* wszMachineName; H323DBG(( DEBUG_LEVEL_TRACE, "ValidateCallParams entered:%p.", this )); H323DBG(( DEBUG_LEVEL_VERBOSE, "clearing unknown media mode." )); // validate pointer if( (pCallParams == NULL) || (pwszDialableAddr == NULL) ) { return FALSE; } // retrieve media modes specified dwMediaModes = pCallParams->dwMediaMode; // retrieve address type specified m_dwAddressType = pCallParams->dwAddressType; // see if we support call parameters if( pCallParams->dwCallParamFlags != 0 ) { H323DBG(( DEBUG_LEVEL_ERROR, "do not support call parameters 0x%08lx.", pCallParams->dwCallParamFlags )); // do not support param flags *pdwStatus = LINEERR_INVALCALLPARAMS; // failure return FALSE; } // see if unknown bit is specified if( dwMediaModes & LINEMEDIAMODE_UNKNOWN ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "clearing unknown media mode." )); // clear unknown bit from modes dwMediaModes &= ~LINEMEDIAMODE_UNKNOWN; } // see if both audio bits are specified if( (dwMediaModes & LINEMEDIAMODE_AUTOMATEDVOICE) && (dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE) ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "clearing automated voice media mode." )); // clear extra audio bit from modes dwMediaModes &= ~LINEMEDIAMODE_INTERACTIVEVOICE; } // see if we support media modes specified if( dwMediaModes & ~H323_LINE_MEDIAMODES ) { H323DBG(( DEBUG_LEVEL_ERROR, "do not support media modes 0x%08lx.", pCallParams->dwMediaMode )); // do not support media mode *pdwStatus = LINEERR_INVALMEDIAMODE; // failure return FALSE; } // see if we support bearer modes if( pCallParams->dwBearerMode & ~H323_LINE_BEARERMODES ) { H323DBG(( DEBUG_LEVEL_ERROR, "do not support bearer mode 0x%08lx.", pCallParams->dwBearerMode )); // do not support bearer mode *pdwStatus = LINEERR_INVALBEARERMODE; // failure return FALSE; } // see if we support address modes if( pCallParams->dwAddressMode & ~H323_LINE_ADDRESSMODES ) { H323DBG(( DEBUG_LEVEL_ERROR, "do not support address mode 0x%08lx.", pCallParams->dwAddressMode )); // do not support address mode *pdwStatus = LINEERR_INVALADDRESSMODE; // failure return FALSE; } // validate address id specified if (pCallParams->dwAddressID != 0 ) { H323DBG(( DEBUG_LEVEL_ERROR, "address id 0x%08lx invalid.", pCallParams->dwAddressID )); // invalid address id *pdwStatus = LINEERR_INVALADDRESSID; // failure return FALSE; } // validate destination address type specified if( m_dwAddressType & ~H323_LINE_ADDRESSTYPES ) { H323DBG(( DEBUG_LEVEL_ERROR, "address type 0x%08lx invalid.", pCallParams->dwAddressType )); // invalid address type *pdwStatus = LINEERR_INVALADDRESSTYPE; //failure return FALSE; } if( m_dwAddressType == LINEADDRESSTYPE_PHONENUMBER ) { dwAddrSize = ValidateE164Address( pwszDialableAddr, wszAddr ); //add the callee alias if( dwAddrSize==0 ) { H323DBG(( DEBUG_LEVEL_ERROR, "invlid e164 callee alias .")); return FALSE; } if( (dwAddrSize > MAX_E164_ADDR_LEN) || (dwAddrSize == 0) ) return FALSE; if(!AddAliasItem( m_pCalleeAliasNames, (BYTE*)wszAddr, dwAddrSize * sizeof(WCHAR), e164_chosen )) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate for callee alias .")); // invalid destination addr *pdwStatus = LINEERR_INVALADDRESS; return FALSE; } H323DBG(( DEBUG_LEVEL_ERROR, "callee alias added:%S.", wszAddr )); } else { dwAddrSize = (wcslen(pwszDialableAddr)+1); if( (dwAddrSize > MAX_H323_ADDR_LEN) || (dwAddrSize == 0) ) return FALSE; if(!AddAliasItem( m_pCalleeAliasNames, (BYTE*)pwszDialableAddr, dwAddrSize * sizeof(WCHAR), h323_ID_chosen )) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate for callee alias .")); // invalid destination addr *pdwStatus = LINEERR_INVALADDRESS; return FALSE; } H323DBG(( DEBUG_LEVEL_ERROR, "callee alias added:%S.", pwszDialableAddr )); } // see if callee alias specified if( pCallParams->dwCalledPartySize > 0 ) { //avoid duplicate aliases dwAddrSize *= sizeof(WCHAR); if( ( (m_dwAddressType != LINEADDRESSTYPE_PHONENUMBER) || (memcmp( (PVOID)((BYTE*)pCallParams + pCallParams->dwCalledPartyOffset), wszAddr, pCallParams->dwCalledPartySize ) != 0 ) ) && ( memcmp( (PVOID)((BYTE*)pCallParams + pCallParams->dwCalledPartyOffset), pwszDialableAddr, pCallParams->dwCalledPartySize ) != 0 ) ) { // allocate memory for callee string if( !AddAliasItem( m_pCalleeAliasNames, (BYTE*)pCallParams + pCallParams->dwCalledPartyOffset, pCallParams->dwCalledPartySize, (m_dwAddressType != LINEADDRESSTYPE_PHONENUMBER)? h323_ID_chosen : e164_chosen) ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate caller name." )); // invalid address id *pdwStatus = LINEERR_NOMEM; // failure return FALSE; } H323DBG(( DEBUG_LEVEL_ERROR, "callee alias added:%S.", ((BYTE*)pCallParams + pCallParams->dwCalledPartyOffset) )); } } // see if caller name specified if( pCallParams->dwCallingPartyIDSize > 0 ) { //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); // allocate memory for callee string if(!AddAliasItem( m_pCallerAliasNames, (BYTE*)pCallParams + pCallParams->dwCallingPartyIDOffset, pCallParams->dwCallingPartyIDSize, h323_ID_chosen ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate caller name." )); // invalid address id *pdwStatus = LINEERR_NOMEM; // failure return FALSE; } //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } else if( RasIsRegistered() ) { //ARQ message must have a caller alias pAliasList = RASGetRegisteredAliasList(); wszMachineName = pAliasList -> pItems[0].pData; //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); //set the value for m_pCallerAliasNames if( !AddAliasItem( m_pCallerAliasNames, (BYTE*)(wszMachineName), sizeof(WCHAR) * (wcslen(wszMachineName) + 1 ), pAliasList -> pItems[0].wType ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate caller name." )); // invalid address id *pdwStatus = LINEERR_NOMEM; // failure return FALSE; } //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } // check for user user information if( pCallParams->dwUserUserInfoSize > 0 ) { // save user user info if (AddU2U( U2U_OUTBOUND, pCallParams->dwUserUserInfoSize, (LPBYTE)pCallParams + pCallParams->dwUserUserInfoOffset ) == FALSE ) { //no need to free above aloocated memory for m_CalleeAlias and //m_CallerAlias // invalid address id *pdwStatus = LINEERR_NOMEM; // failure return FALSE; } } // save call data buffer. if( SetCallData( (LPBYTE)pCallParams + pCallParams->dwCallDataOffset, pCallParams->dwCallDataSize ) == FALSE ) { //no need to free above aloocated memory for m_CalleeAlias and //m_CallerAlias // invalid address id *pdwStatus = LINEERR_NOMEM; // failure return FALSE; } // clear incoming modes m_dwIncomingModes = 0; // outgoing modes will be finalized after H.245 stage m_dwOutgoingModes = dwMediaModes | LINEMEDIAMODE_UNKNOWN; // save media modes specified m_dwRequestedModes = dwMediaModes; H323DBG(( DEBUG_LEVEL_TRACE, "ValidateCallParams exited:%p.", this )); // success return TRUE; } /*++ Routine Description: Associates call object with the specified conference id. Arguments: Return Values: Returns true if successful. --*/ PH323_CONFERENCE CH323Call::CreateConference ( IN GUID* pConferenceId OPTIONAL) { int iresult; H323DBG(( DEBUG_LEVEL_TRACE, "CreateConference entered:%p.", this )); Lock(); _ASSERTE( m_hdConf == NULL ); // create conference m_hdConf = new H323_CONFERENCE( this ); // validate if ( m_hdConf == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "could no allocate the conference object.")); Unlock(); return NULL; } if (pConferenceId) { m_ConferenceID = *pConferenceId; } else { iresult = UuidCreate (&m_ConferenceID); if ((iresult == RPC_S_OK) || (iresult ==RPC_S_UUID_LOCAL_ONLY)) { H323DBG ((DEBUG_LEVEL_INFO, "generated new conference id (GUID).")); } else { H323DBG(( DEBUG_LEVEL_ERROR, "failed to generate GUID for conference id: %d.", iresult )); ZeroMemory (&m_ConferenceID, sizeof m_ConferenceID); } } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "CreateConference exited:%p.", this )); return m_hdConf; } /*++ Routine Description: Initiates outbound call to specified destination. !!always called in a lock Arguments: none Return Values: Returns true if successful. --*/ BOOL CH323Call::PlaceCall(void) { H323DBG(( DEBUG_LEVEL_TRACE, "PlaceCall entered:%p.", this )); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { return FALSE; } // see if user user information specified CopyU2UAsNonStandard( U2U_OUTBOUND ); if( m_pwszDisplay == NULL ) { // see if caller alias specified if( m_pCallerAliasNames && m_pCallerAliasNames -> wCount ) { if((m_pCallerAliasNames ->pItems[0].wType == h323_ID_chosen) || (m_pCallerAliasNames ->pItems[0].wType == e164_chosen) ) { // send caller name as display m_pwszDisplay = m_pCallerAliasNames -> pItems[0].pData; //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } } // validate if( !SetupCall() ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "Q931 call: failed." )); return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "PlaceCall exited:%p.", this )); // return status return TRUE; } void CH323Call::DropUserInitiated( IN DWORD dwDisconnectMode ) { //since this is a user initiated drop, the transfered call should also //be dropped for a primary call and vice versa if( IsTransferredCall( m_dwCallType ) && m_hdRelatedCall ) { QueueTAPILineRequest( TSPI_CLOSE_CALL, m_hdRelatedCall, NULL, dwDisconnectMode, m_wCallReference ); } DropCall(dwDisconnectMode); } //always called in lock BOOL /*++ Routine Description: Hangs up call (if necessary) and changes state to idle. Arguments: dwDisconnectMode - Status code for disconnect. Return Values: Returns true if successful. --*/ CH323Call::DropCall( IN DWORD dwDisconnectMode ) { PUserToUserLE pU2ULE = NULL; if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "DropCall entered:%p.", this )); if( (m_dwRASCallState == RASCALL_STATE_REGISTERED ) || (m_dwRASCallState == RASCALL_STATE_ARQSENT ) ) { //disengage from the GK SendDRQ( forcedDrop_chosen, NOT_RESEND_SEQ_NUM, TRUE ); } // determine call state switch (m_dwCallState) { case LINECALLSTATE_CONNECTED: // hangup call (this will invoke async indication) // validate //encode ASN.1 and send Q931release message to the peer if(!SendQ931Message( NO_INVOKEID, 0, 0, RELEASECOMPLMESSAGETYPE, NO_H450_APDU )) { //post a message to the callback thread to shutdown the H323 call H323DBG(( DEBUG_LEVEL_ERROR, "error hanging up call 0x%08lx.", this )); } else { m_dwStateMachine = Q931_RELEASE_SENT; H323DBG(( DEBUG_LEVEL_VERBOSE, "call 0x%08lx hung up.", this )); } // change call state to disconnected ChangeCallState(LINECALLSTATE_DISCONNECTED, dwDisconnectMode); break; case LINECALLSTATE_OFFERING: // see if user user information specified CopyU2UAsNonStandard( U2U_OUTBOUND ); // reject call //encode ASN.1 and send Q931Setup message to the peer if( SendQ931Message( NO_INVOKEID, 0, 0, RELEASECOMPLMESSAGETYPE, NO_H450_APDU )) { m_dwStateMachine = Q931_RELEASE_SENT; H323DBG(( DEBUG_LEVEL_VERBOSE, "call 0x%08lx rejected.", this )); } else { H323DBG(( DEBUG_LEVEL_ERROR, "error reject call 0x%08lx.",this)); } // change call state to disconnected ChangeCallState(LINECALLSTATE_DISCONNECTED, dwDisconnectMode); break; case LINECALLSTATE_RINGBACK: case LINECALLSTATE_ACCEPTED: // cancel outbound call if( SendQ931Message( NO_INVOKEID, 0, 0, RELEASECOMPLMESSAGETYPE, NO_H450_APDU )) { H323DBG(( DEBUG_LEVEL_ERROR, "error cancelling call 0x%08lx.", this )); } else { H323DBG(( DEBUG_LEVEL_ERROR, "error reject call 0x%08lx.", this )); } // change call state to disconnected ChangeCallState(LINECALLSTATE_DISCONNECTED, dwDisconnectMode); break; case LINECALLSTATE_DIALING: // change call state to disconnected ChangeCallState(LINECALLSTATE_DISCONNECTED, dwDisconnectMode); break; case LINECALLSTATE_DISCONNECTED: // // disconnected but still need to clean up // break; case LINECALLSTATE_IDLE: // // call object already idle // if( (m_dwCallType == CALLTYPE_NORMAL) && (m_dwStateMachine == Q931_SETUP_RECVD) ) { if( SendQ931Message( NO_INVOKEID, 0, 0, RELEASECOMPLMESSAGETYPE, NO_H450_APDU )) { H323DBG(( DEBUG_LEVEL_ERROR, "error cancelling call 0x%08lx.", this )); } else { H323DBG(( DEBUG_LEVEL_ERROR, "error reject call 0x%08lx.", this )); } } DropSupplementaryServicesCalls(); return TRUE; } if( ( (m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall ) || ( (m_dwCallType & CALLTYPE_TRANSFEREDSRC ) && m_hdRelatedCall ) ) { m_dwCallState = LINECALLSTATE_IDLE; } else { // Tell the MSP to stop streaming. SendMSPMessage( SP_MSG_CallShutdown, 0, 0, NULL ); // change call state to idle ChangeCallState( LINECALLSTATE_IDLE, 0 ); } if( (m_dwCallType & CALLTYPE_TRANSFEREDSRC ) && m_hdRelatedCall ) { //drop the primary call if( !QueueTAPILineRequest( TSPI_CLOSE_CALL, m_hdRelatedCall, NULL, LINEDISCONNECTMODE_NORMAL, NULL ) ) { H323DBG((DEBUG_LEVEL_ERROR, "could not post H323 close event")); } } H323DBG(( DEBUG_LEVEL_TRACE, "DropCall exited:%p.", this )); // success return TRUE; } void CH323Call::DropSupplementaryServicesCalls() { if( (m_dwCallType & CALLTYPE_FORWARDCONSULT) || (m_dwCallType & CALLTYPE_DIVERTED_SERVED) || (m_dwCallType & CALLTYPE_DIVERTEDSRC) || (m_dwCallType & CALLTYPE_DIVERTEDSRC_NOROUTING) ) { if( m_dwQ931Flags & Q931_CALL_CONNECTED ) { if( SendQ931Message( NO_INVOKEID, 0, 0, RELEASECOMPLMESSAGETYPE, NO_H450_APDU )) { m_dwStateMachine = Q931_RELEASE_SENT; H323DBG(( DEBUG_LEVEL_VERBOSE, "call 0x%08lx rejected.", this )); } } g_pH323Line->m_fForwardConsultInProgress = FALSE; } if( (m_dwCallType & CALLTYPE_FORWARDCONSULT) && (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //inform the user about failure of line forward operation if( m_dwCallDiversionState != H4503_CHECKRESTRICTION_SUCC ) { (*g_pfnLineEventProc)( g_pH323Line->m_htLine, (HTAPICALL)NULL, (DWORD)LINE_ADDRESSSTATE, (DWORD)LINEADDRESSSTATE_FORWARD, (DWORD)LINEADDRESSSTATE_FORWARD, (DWORD)0 ); } } if( m_dwCallType & CALLTYPE_DIVERTEDSRC ) { ChangeCallState( LINECALLSTATE_IDLE, 0 ); } } //!!always called in a lock BOOL CH323Call::HandleConnectMessage( IN Q931_CONNECT_ASN *pConnectASN ) { PH323_CALL pPrimaryCall = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "HandleConnectMessage entered:%p.", this )); if( pConnectASN->fNonStandardDataPresent ) { //add user user info if( AddU2UNoAlloc( U2U_INBOUND, pConnectASN->nonStandardData.sData.wOctetStringLength, pConnectASN->nonStandardData.sData.pOctetString ) == TRUE ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "user user info available in CONNECT PDU." )); if( !(m_dwCallType & CALLTYPE_TRANSFEREDSRC) ) { // signal incoming PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_USERUSERINFO, 0, 0 ); } //don't release the data buffer pConnectASN->fNonStandardDataPresent = FALSE; } else { H323DBG(( DEBUG_LEVEL_WARNING, "could not save incoming user user info." )); //memory failure : shutdown the H323 call CloseCall( 0 ); goto cleanup; } } //get the vendor info if( pConnectASN->EndpointType.pVendorInfo ) { FreeVendorInfo( &m_peerVendorInfo ); m_peerVendorInfo = pConnectASN->VendorInfo; pConnectASN->EndpointType.pVendorInfo = NULL; } if( pConnectASN->h245AddrPresent ) { m_peerH245Addr = pConnectASN->h245Addr; } //copy the fast start proposal if( pConnectASN->fFastStartPresent && (m_dwFastStart!=FAST_START_NOTAVAIL) ) { if( m_pPeerFastStart ) { //we had received fast start params in previous proceeding //or alerting message FreeFastStart( m_pPeerFastStart ); } m_pPeerFastStart = pConnectASN->pFastStart; m_dwFastStart = FAST_START_AVAIL; //we are keeping a reference to the fast start list so don't release it pConnectASN->pFastStart = NULL; } else { m_dwFastStart = FAST_START_NOTAVAIL; } if( ( (m_dwCallType & CALLTYPE_TRANSFEREDSRC)|| (m_dwCallType & CALLTYPE_DIVERTEDTRANSFERED) ) && m_hdRelatedCall ) { QueueSuppServiceWorkItem( SWAP_REPLACEMENT_CALL, m_hdCall, (ULONG_PTR)m_hdRelatedCall ); } else { //start H245 SendMSPStartH245( NULL, NULL ); SendMSPMessage( SP_MSG_ConnectComplete, 0, 0, NULL ); } //If we join MCU we get the conference ID of the conference we //joined and not the one that we sent in Setup message. if( IsEqualConferenceID( &pConnectASN->ConferenceID ) == FALSE ) { H323DBG ((DEBUG_LEVEL_ERROR, "OnReceiveConnect: We received different conference id." )); m_ConferenceID = pConnectASN->ConferenceID; } //tell TAPI about state change ChangeCallState( LINECALLSTATE_CONNECTED, 0 ); FreeConnectASN( pConnectASN ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleConnectMessage exited:%p.", this )); return TRUE; cleanup: FreeConnectASN( pConnectASN ); return FALSE; } //!!always called in a lock void CH323Call::HandleAlertingMessage( IN Q931_ALERTING_ASN * pAlertingASN ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleAlertingMessage entered:%p.", this )); if( pAlertingASN->fNonStandardDataPresent ) { // add user user info if( AddU2UNoAlloc( U2U_INBOUND, pAlertingASN->nonStandardData.sData.wOctetStringLength, pAlertingASN->nonStandardData.sData.pOctetString ) == TRUE ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "user user info available in ALERT PDU." )); // signal incoming if( !(m_dwCallType & CALLTYPE_TRANSFEREDSRC) ) { PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_USERUSERINFO, 0, 0 ); } //don't release the data buffer pAlertingASN->fNonStandardDataPresent = FALSE; } else { H323DBG(( DEBUG_LEVEL_WARNING, "could not save incoming user user info." )); //memory failure : shutdown the H323 call CloseCall( 0 ); return; } } if( pAlertingASN->fH245AddrPresent ) { m_peerH245Addr = pAlertingASN->h245Addr; } if( pAlertingASN->fFastStartPresent && (m_dwFastStart!=FAST_START_NOTAVAIL) ) { if( m_pPeerFastStart ) { //we had received fast start params in previous proceeding //or alerting message FreeFastStart( m_pPeerFastStart ); } m_pPeerFastStart = pAlertingASN->pFastStart; m_dwFastStart = FAST_START_AVAIL; //we are keeping a reference to the fast start list so don't release it pAlertingASN->pFastStart = NULL; pAlertingASN->fFastStartPresent = FALSE; } //for DIVERTEDSRC, call its ok to tell TAPI about this state ChangeCallState( LINECALLSTATE_RINGBACK, 0 ); /*if( pAlertingASN->fH245AddrPresent && !(m_dwFlags & H245_START_MSG_SENT) ) { //start early H245 SendMSPStartH245( NULL, NULL); }*/ FreeAlertingASN( pAlertingASN ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleAlertingMessage exited:%p.", this )); return; } //!!must be always called in a lock BOOL CH323Call::HandleSetupMessage( IN Q931MESSAGE* pMessage ) { PH323_ALIASITEM pwszDivertedToAlias = NULL; WCHAR * pwszAliasName = NULL; WORD wAliasLength = 0; H323DBG(( DEBUG_LEVEL_TRACE, "HandleSetupMessage entered:%p.", this )); if( m_pCallerAliasNames && (m_pCallerAliasNames -> wCount > 0) ) { pwszAliasName = m_pCallerAliasNames->pItems[0].pData; wAliasLength = (m_pCallerAliasNames->pItems[0].wDataLength+1) * sizeof(WCHAR); //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } pwszDivertedToAlias = g_pH323Line->CallToBeDiverted( pwszAliasName, wAliasLength, LINEFORWARDMODE_UNCOND | LINEFORWARDMODE_UNCONDSPECIFIC ); if( pwszDivertedToAlias ) { if( !InitiateCallDiversion( pwszDivertedToAlias, DiversionReason_cfu ) ) { return FALSE; } return TRUE; } //send the proceeding message to the peer if not already sent by the GK //SendProceeding(); if(RasIsRegistered()) { if( !SendARQ( NOT_RESEND_SEQ_NUM ) ) { return FALSE; } //copy the data to be sent in preparetoanswer message if( m_prepareToAnswerMsgData.pbBuffer ) delete m_prepareToAnswerMsgData.pbBuffer; ZeroMemory( (PVOID)&m_prepareToAnswerMsgData, sizeof(BUFFERDESCR) ); m_prepareToAnswerMsgData.pbBuffer = (BYTE*)new char[pMessage->UserToUser.wUserInfoLen]; if( m_prepareToAnswerMsgData.pbBuffer == NULL ) { return FALSE; } CopyMemory( (PVOID)m_prepareToAnswerMsgData.pbBuffer, (PVOID)pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen ); m_prepareToAnswerMsgData.dwLength = pMessage->UserToUser.wUserInfoLen; } else { if( (m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall ) { MSPMessageData* pMSPMessageData = new MSPMessageData; if( pMSPMessageData == NULL ) { return FALSE; } pMSPMessageData->hdCall = m_hdRelatedCall; pMSPMessageData->messageType = SP_MSG_PrepareToAnswer; pMSPMessageData->pbEncodedBuf = new BYTE[pMessage->UserToUser.wUserInfoLen]; if( pMSPMessageData->pbEncodedBuf == NULL ) { delete pMSPMessageData; return FALSE; } CopyMemory( pMSPMessageData->pbEncodedBuf, (PVOID)pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen ); pMSPMessageData->wLength = pMessage->UserToUser.wUserInfoLen; pMSPMessageData->hReplacementCall = m_hdCall; if( !QueueUserWorkItem( SendMSPMessageOnRelatedCall, pMSPMessageData, WT_EXECUTEDEFAULT ) ) { delete pMSPMessageData->pbEncodedBuf; delete pMSPMessageData; return FALSE; } } else { // signal incoming call _ASSERTE(!m_htCall); PostLineEvent ( LINE_NEWCALL, (DWORD_PTR)m_hdCall, (DWORD_PTR)&m_htCall, 0); _ASSERTE( m_htCall ); if( m_htCall == NULL ) return FALSE; if( IsListEmpty(&m_IncomingU2U) == FALSE ) { // signal incoming PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_USERUSERINFO, 0, 0); } ChangeCallState( LINECALLSTATE_OFFERING, 0 ); //Send the new call message to the unspecified MSP SendMSPMessage( SP_MSG_PrepareToAnswer, pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, NULL ); } } H323DBG(( DEBUG_LEVEL_TRACE, "HandleSetupMessage exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleCallDiversionFacility( PH323_ADDR pAlternateAddress ) { PSTR pszAlias; WCHAR pwszAliasName[H323_MAXDESTNAMELEN]; in_addr addr; if( m_pCallReroutingInfo == NULL ) { m_pCallReroutingInfo = new CALLREROUTINGINFO; if( m_pCallReroutingInfo == NULL ) { return FALSE; } ZeroMemory( (PVOID)m_pCallReroutingInfo, sizeof(CALLREROUTINGINFO) ); } m_pCallReroutingInfo->diversionCounter = 1; m_pCallReroutingInfo->diversionReason = DiversionReason_cfu; //free any previous divertedTo alias if( m_pCallReroutingInfo->divertedToNrAlias ) { FreeAliasNames( m_pCallReroutingInfo->divertedToNrAlias ); m_pCallReroutingInfo->divertedToNrAlias = NULL; } addr.S_un.S_addr = htonl( pAlternateAddress->Addr.IP_Binary.dwAddr ); pszAlias = inet_ntoa( addr ); if( pszAlias == NULL ) return FALSE; m_pCallReroutingInfo->divertedToNrAlias = new H323_ALIASNAMES; if( m_pCallReroutingInfo->divertedToNrAlias == NULL ) { return FALSE; } ZeroMemory( m_pCallReroutingInfo->divertedToNrAlias, sizeof(H323_ALIASNAMES) ); MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, pszAlias, strlen(pszAlias)+1, pwszAliasName, H323_MAXDESTNAMELEN ); if( !AddAliasItem( m_pCallReroutingInfo->divertedToNrAlias, pwszAliasName, h323_ID_chosen ) ) { delete m_pCallReroutingInfo->divertedToNrAlias; m_pCallReroutingInfo->divertedToNrAlias = NULL; return FALSE; } m_CalleeAddr = *pAlternateAddress; if( m_pCalleeAliasNames && m_pCalleeAliasNames->wCount ) { m_pCallReroutingInfo->divertingNrAlias = new H323_ALIASNAMES; if( m_pCallReroutingInfo->divertingNrAlias != NULL ) { ZeroMemory( (PVOID)m_pCallReroutingInfo->divertingNrAlias, sizeof(H323_ALIASNAMES) ); if( !AddAliasItem( m_pCallReroutingInfo->divertingNrAlias, m_pCalleeAliasNames->pItems[0].pData, m_pCalleeAliasNames->pItems[0].wType ) ) { delete m_pCallReroutingInfo->divertingNrAlias; m_pCallReroutingInfo->divertingNrAlias = NULL; } } } m_dwCallType |= CALLTYPE_DIVERTEDSRC; m_dwCallDiversionState = H4503_CALLREROUTING_RECVD; H323DBG(( DEBUG_LEVEL_TRACE, "HandleCallDiversionFacility exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleCallDiversionFacility( PH323_ALIASNAMES pAliasList ) { if( !m_pCallReroutingInfo ) { m_pCallReroutingInfo = new CALLREROUTINGINFO; if( m_pCallReroutingInfo == NULL ) { return FALSE; } ZeroMemory( (PVOID)m_pCallReroutingInfo, sizeof(CALLREROUTINGINFO) ); } m_pCallReroutingInfo->diversionCounter = 1; m_pCallReroutingInfo->diversionReason = DiversionReason_cfu; if( m_pCallReroutingInfo->divertedToNrAlias ) { FreeAliasNames( m_pCallReroutingInfo->divertedToNrAlias ); m_pCallReroutingInfo->divertedToNrAlias = NULL; } m_pCallReroutingInfo->divertedToNrAlias = pAliasList; if( m_pCalleeAliasNames && m_pCalleeAliasNames->wCount ) { m_pCallReroutingInfo->divertingNrAlias = new H323_ALIASNAMES; if( m_pCallReroutingInfo->divertingNrAlias != NULL ) { ZeroMemory( (PVOID)m_pCallReroutingInfo->divertingNrAlias, sizeof(H323_ALIASNAMES) ); if( !AddAliasItem( m_pCallReroutingInfo->divertingNrAlias, m_pCalleeAliasNames->pItems[0].pData, m_pCalleeAliasNames->pItems[0].wType ) ) { delete m_pCallReroutingInfo->divertingNrAlias; m_pCallReroutingInfo->divertingNrAlias = NULL; } } } m_dwCallType |= CALLTYPE_DIVERTEDSRC; m_dwCallDiversionState = H4503_CALLREROUTING_RECVD; H323DBG(( DEBUG_LEVEL_TRACE, "HandleCallDiversionFacility exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleTransferFacility( PH323_ALIASNAMES pAliasList ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleTransferFacility entered:%p.", this )); //argument.callIdentity ZeroMemory( (PVOID)m_pCTCallIdentity, sizeof(m_pCTCallIdentity) ); //argument.reroutingNumber FreeAliasNames( m_pTransferedToAlias ); m_pTransferedToAlias = pAliasList; m_dwCallType |= CALLTYPE_TRANSFERED_PRIMARY; m_dwCallDiversionState = H4502_CTINITIATE_RECV; //queue an event for creating a new call if( !QueueSuppServiceWorkItem( TSPI_DIAL_TRNASFEREDCALL, m_hdCall, (ULONG_PTR)m_pTransferedToAlias )) { H323DBG(( DEBUG_LEVEL_TRACE, "could not post dial transfer event." )); } H323DBG(( DEBUG_LEVEL_TRACE, "HandleTransferFacility entered:%p.", this )); return TRUE; } BOOL CH323Call::HandleTransferFacility( PH323_ADDR pAlternateAddress ) { PSTR pszAlias; WCHAR pwszAliasName[H323_MAXDESTNAMELEN]; in_addr addr; H323DBG(( DEBUG_LEVEL_TRACE, "HandleTransferFacility entered:%p.", this )); //argument.callIdentity ZeroMemory( (PVOID)m_pCTCallIdentity, sizeof(m_pCTCallIdentity) ); //argument.reroutingNumber //free any previous divertedTo alias FreeAliasNames( m_pTransferedToAlias ); addr.S_un.S_addr = htonl( pAlternateAddress->Addr.IP_Binary.dwAddr ); pszAlias = inet_ntoa( addr ); if( pszAlias == NULL ) { return FALSE; } m_pTransferedToAlias = new H323_ALIASNAMES; if( m_pTransferedToAlias == NULL ) { return FALSE; } ZeroMemory( m_pTransferedToAlias, sizeof(H323_ALIASNAMES) ); MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, pszAlias, strlen(pszAlias)+1, pwszAliasName, H323_MAXDESTNAMELEN ); if( !AddAliasItem( m_pTransferedToAlias, pwszAliasName, h323_ID_chosen ) ) { delete m_pTransferedToAlias; m_pTransferedToAlias = NULL; return FALSE; } m_CalleeAddr = *pAlternateAddress; m_dwCallType |= CALLTYPE_TRANSFERED_PRIMARY; m_dwCallDiversionState = H4502_CTINITIATE_RECV; //queue an event for creating a new call if( !QueueSuppServiceWorkItem( TSPI_DIAL_TRNASFEREDCALL, m_hdCall, (ULONG_PTR)m_pTransferedToAlias )) { H323DBG(( DEBUG_LEVEL_TRACE, "could not post dial transfer event." )); } H323DBG(( DEBUG_LEVEL_TRACE, "HandleTransferFacility entered:%p.", this )); return TRUE; } //!!always called in a lock void CH323Call::HandleFacilityMessage( IN DWORD dwInvokeID, IN Q931_FACILITY_ASN * pFacilityASN ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleFacilityMessage entered:%p.", this )); if( pFacilityASN->fNonStandardDataPresent ) { // add user user info if( AddU2UNoAlloc( U2U_INBOUND, pFacilityASN->nonStandardData.sData.wOctetStringLength, pFacilityASN->nonStandardData.sData.pOctetString ) == TRUE ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "user user info available in ALERT PDU." )); // signal incoming if( !(m_dwCallType & CALLTYPE_TRANSFEREDSRC) ) { PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_USERUSERINFO, 0, 0); } //don't release the data buffer pFacilityASN->fNonStandardDataPresent = FALSE; } else { H323DBG(( DEBUG_LEVEL_WARNING, "could not save incoming user user info." )); //memory failure : shutdown the H323 call CloseCall( 0 ); return; } } if( (pFacilityASN->bReason == callForwarded_chosen) || (pFacilityASN->bReason == FacilityReason_routeCallToGatekeeper_chosen) || (pFacilityASN->bReason == routeCallToMC_chosen) ) { if( pFacilityASN->pAlternativeAliasList != NULL ) { if( m_dwCallState == LINECALLSTATE_CONNECTED ) { HandleTransferFacility( pFacilityASN->pAlternativeAliasList ); //don't free the alias list pFacilityASN->pAlternativeAliasList = NULL; } else if( m_dwCallState != LINECALLSTATE_DISCONNECTED ) { //redirect the call if not yet connected if( HandleCallDiversionFacility( pFacilityASN->pAlternativeAliasList ) ) { OnCallReroutingReceive( NO_INVOKEID ); //don't free the alias list pFacilityASN->pAlternativeAliasList = NULL; } } } else if( pFacilityASN->fAlternativeAddressPresent ) { if( m_dwCallState == LINECALLSTATE_CONNECTED ) { HandleTransferFacility( &pFacilityASN->AlternativeAddr ); } else if( m_dwCallState != LINECALLSTATE_DISCONNECTED ) { //redirect the call if not yet connected if( HandleCallDiversionFacility( &pFacilityASN->AlternativeAddr ) ) { OnCallReroutingReceive( NO_INVOKEID ); } } } } //Handle H.450 APDU if( pFacilityASN->dwH450APDUType == DIVERTINGLEGINFO1_OPCODE ) { if( m_dwOrigin != LINECALLORIGIN_OUTBOUND ) { return; } if( m_pCallReroutingInfo && m_pCallReroutingInfo->fPresentAllow ) { PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_REDIRECTINGID, 0, 0); } } else if( pFacilityASN->dwH450APDUType == CALLREROUTING_OPCODE ) { OnCallReroutingReceive( dwInvokeID ); } else if( pFacilityASN->dwH450APDUType == REMOTEHOLD_OPCODE ) { if( m_fRemoteHoldInitiated ) { //Hold(); m_fRemoteHoldInitiated = FALSE; } } else if( pFacilityASN->dwH450APDUType == REMOTERETRIEVE_OPCODE ) { if( m_fRemoteRetrieveInitiated ) { //UnHold(); m_fRemoteRetrieveInitiated = FALSE; } } else if( pFacilityASN->fH245AddrPresent ) { m_peerH245Addr = pFacilityASN->h245Addr; H323DBG(( DEBUG_LEVEL_TRACE, "H245 address received in facility." )); //If Q931 call already connected then send another StartH245. if( m_dwCallState == LINECALLSTATE_CONNECTED ) { SendMSPStartH245( NULL, NULL ); } } H323DBG(( DEBUG_LEVEL_TRACE, "HandleFacilityMessage exited:%p.", this )); return; } void CH323Call::SetNewCallInfo( HANDLE hConnWait, HANDLE hWSAEvent, DWORD dwState ) { H323DBG(( DEBUG_LEVEL_TRACE, "SetNewCallInfo entered." )); Lock(); m_hTransportWait = hConnWait; m_hTransport = hWSAEvent; SetQ931CallState( dwState ); Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "SetNewCallInfo exited." )); } //!!no need to call in a lock void CH323Call::SetQ931CallState( DWORD dwState ) { H323DBG(( DEBUG_LEVEL_TRACE, "SetQ931CallState entered." )); //turn off the current state m_dwQ931Flags &= ~(Q931_CALL_CONNECTING | Q931_CALL_CONNECTED | Q931_CALL_DISCONNECTED ); //set the new state m_dwQ931Flags |= dwState; H323DBG(( DEBUG_LEVEL_TRACE, "SetQ931CallState exited." )); } void CH323Call::DialCall() { H323DBG(( DEBUG_LEVEL_TRACE, "DialCall entered:%p.", this )); Lock(); ChangeCallState( LINECALLSTATE_DIALING, 0); if( RasIsRegistered() ) { if( !SendARQ( NOT_RESEND_SEQ_NUM ) ) { //If a forward consult call then enable theforwarding anyway. if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //Success of forwarding EnableCallForwarding(); } CloseCall( 0 ); } } else { if( !PlaceCall() ) { //If a forward consult call then enable theforwarding anyway. if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //Success of forwarding EnableCallForwarding(); } CloseCall( LINEDISCONNECTMODE_UNREACHABLE ); } } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "DialCall exited:%p.", this )); } //!!always called in a lock void CH323Call::MakeCall() { H323DBG(( DEBUG_LEVEL_TRACE, "MakeCall entered:%p.", this )); ChangeCallState( LINECALLSTATE_DIALING, 0 ); // resolve dialable into local and remote address if( !RasIsRegistered() && !ResolveAddress( GetDialableAddress() ) ) { CloseCall( LINEDISCONNECTMODE_BADADDRESS ); } else { if( RasIsRegistered() ) { if( !SendARQ( NOT_RESEND_SEQ_NUM ) ) { //If a forward consult call then enable theforwarding anyway. if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //Success of forwarding EnableCallForwarding(); } CloseCall( 0 ); } } else { if( !PlaceCall() ) { //If a forward consult call then enable theforwarding anyway. if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //Success of forwarding EnableCallForwarding(); } CloseCall( LINEDISCONNECTMODE_UNREACHABLE ); } } } H323DBG(( DEBUG_LEVEL_TRACE, "MakeCall exited:%p.", this )); } //!!always called in a lock void CH323Call::HandleProceedingMessage( IN Q931_ALERTING_ASN * pProceedingASN ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleProceedingMessage entered:%p.", this )); if( pProceedingASN->fNonStandardDataPresent ) { // add user user info if( AddU2UNoAlloc( U2U_INBOUND, pProceedingASN->nonStandardData.sData.wOctetStringLength, pProceedingASN->nonStandardData.sData.pOctetString ) == TRUE ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "user user info available in ALERT PDU." )); // signal incoming if( !(m_dwCallType & CALLTYPE_TRANSFEREDSRC) ) { PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_USERUSERINFO, 0, 0); } //don't release the data buffer pProceedingASN->fNonStandardDataPresent = FALSE; } else { H323DBG(( DEBUG_LEVEL_WARNING, "could not save incoming user user info." )); //memory failure : shutdown the H323 call CloseCall( 0 ); return; } } if( pProceedingASN->fH245AddrPresent ) { m_peerH245Addr = pProceedingASN->h245Addr; } if( pProceedingASN->fFastStartPresent && (m_dwFastStart!=FAST_START_NOTAVAIL) ) { if( m_pPeerFastStart ) { //we had received fast start params in previous proceeding //or alerting message FreeFastStart( m_pPeerFastStart ); } m_pPeerFastStart = pProceedingASN->pFastStart; m_dwFastStart = FAST_START_AVAIL; //we are keeping a reference to the fast start list so don't release it pProceedingASN->pFastStart = NULL; pProceedingASN->fFastStartPresent = FALSE; } /* if( pProceedingASN->fH245AddrPresent && !(m_dwFlags & H245_START_MSG_SENT) ) { //start early H245 SendMSPStartH245( NULL, NULL ); }*/ FreeProceedingASN( pProceedingASN ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleProceedingMessage exited:%p.", this )); return; } //!!always called in a lock BOOL CH323Call::HandleReleaseMessage( IN Q931_RELEASE_COMPLETE_ASN *pReleaseASN ) { DWORD dwDisconnectMode = LINEDISCONNECTMODE_NORMAL; H323DBG(( DEBUG_LEVEL_TRACE, "HandleReleaseMessage entered:%p.", this )); if( (m_dwCallType & CALLTYPE_TRANSFERED_PRIMARY) && (m_hdRelatedCall != NULL) ) { return QueueSuppServiceWorkItem( DROP_PRIMARY_CALL, m_hdRelatedCall, (ULONG_PTR)m_hdCall ); } //change the state to disconnected before callong drop call. //This will ensure that release message is not sent to the peer ChangeCallState( LINECALLSTATE_DISCONNECTED, 0 ); //release non standard data if( pReleaseASN->fNonStandardDataPresent ) { delete pReleaseASN->nonStandardData.sData.pOctetString; pReleaseASN->nonStandardData.sData.pOctetString = NULL; } //Should we drop the primary call if the transfered call in rejected? if( (m_dwCallType == CALLTYPE_TRANSFEREDSRC) && m_hdRelatedCall ) { if( !QueueTAPILineRequest( TSPI_CLOSE_CALL, m_hdRelatedCall, NULL, LINEDISCONNECTMODE_NORMAL, NULL ) ) { H323DBG((DEBUG_LEVEL_ERROR, "could not post H323 close event")); } } //close call if( m_dwCallState != LINECALLSTATE_CONNECTED ) { dwDisconnectMode = LINEDISCONNECTMODE_REJECT; } CloseCall( dwDisconnectMode ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleReleaseMessage exited:%p.", this )); return TRUE; } //never call in lock BOOL CH323Call::InitializeIncomingCall( IN Q931_SETUP_ASN* pSetupASN, IN DWORD dwCallType, IN WORD wCallRef ) { PH323_CONFERENCE pConf; WCHAR* wszMachineName; H323DBG((DEBUG_LEVEL_TRACE, "InitializeIncomingCall entered:%p.",this)); //bind outgoing call pConf = CreateConference( &(pSetupASN->ConferenceID) ); if( pConf == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not create conference." )); goto cleanup; } if( !g_pH323Line -> GetH323ConfTable() -> Add( pConf ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not add conf to conf table." )); // failure goto cleanup; } // save caller transport address if( !GetPeerAddress(&m_CallerAddr) ) { goto cleanup; } if( !GetHostAddress(&m_CalleeAddr) ) { goto cleanup; } //get endpoint info m_peerEndPointType = pSetupASN->EndpointType; //get the vendor info if( pSetupASN->EndpointType.pVendorInfo ) { m_peerVendorInfo = pSetupASN->VendorInfo; //we have copied the vendor info pointers. So dont release //the pointers in the ASN's vendor info struct pSetupASN->EndpointType.pVendorInfo = NULL; } if( pSetupASN -> fCallIdentifierPresent ) { m_callIdentifier = pSetupASN->callIdentifier; } else { int iresult = UuidCreate( &m_callIdentifier ); if( (iresult != RPC_S_OK) && (iresult !=RPC_S_UUID_LOCAL_ONLY) ) { goto cleanup; } } _ASSERTE( !m_pPeerFastStart ); if( pSetupASN->fFastStartPresent && (m_dwFastStart!=FAST_START_NOTAVAIL) ) { m_pPeerFastStart = pSetupASN->pFastStart; m_dwFastStart = FAST_START_PEER_AVAIL; //we are keeping a reference to the fast start list so don't release it pSetupASN->pFastStart = NULL; pSetupASN->fFastStartPresent = FALSE; } else { m_dwFastStart = FAST_START_NOTAVAIL; } //get the alias names if( pSetupASN->pCalleeAliasList ) { _ASSERTE( m_pCalleeAliasNames ); delete m_pCalleeAliasNames; m_pCalleeAliasNames = pSetupASN->pCalleeAliasList; pSetupASN->pCalleeAliasList = NULL; } else { if( RasIsRegistered() ) { PH323_ALIASNAMES pAliasList = RASGetRegisteredAliasList(); AddAliasItem( m_pCalleeAliasNames, pAliasList->pItems[0].pData, pAliasList->pItems[0].wType ); } else { wszMachineName = g_pH323Line->GetMachineName(); //set the value for m_pCalleeAliasNames AddAliasItem( m_pCalleeAliasNames, (BYTE*)(wszMachineName), sizeof(WCHAR) * (wcslen(wszMachineName) + 1 ), h323_ID_chosen ); } } _ASSERTE( m_pCallerAliasNames ); delete m_pCallerAliasNames; m_pCallerAliasNames = NULL; if( pSetupASN->pCallerAliasList ) { m_pCallerAliasNames = pSetupASN->pCallerAliasList; pSetupASN->pCallerAliasList = NULL; //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } if( pSetupASN->pExtraAliasList ) { m_pPeerExtraAliasNames = pSetupASN->pExtraAliasList; pSetupASN->pExtraAliasList = NULL; } //non -standard info if( pSetupASN->fNonStandardDataPresent ) { // add user user info if( AddU2UNoAlloc( U2U_INBOUND, pSetupASN->nonStandardData.sData.wOctetStringLength, pSetupASN->nonStandardData.sData.pOctetString ) == TRUE ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "user user info available in Setup PDU." )); //don't release the data buffer pSetupASN->fNonStandardDataPresent = FALSE; } else { H323DBG(( DEBUG_LEVEL_WARNING, "could not save incoming user user info." )); goto cleanup; } } if( pSetupASN->fSourceAddrPresent ) { m_CallerAddr = pSetupASN->sourceAddr; } m_dwCallType = dwCallType; if( wCallRef ) { m_wQ931CallRef = (wCallRef | 0x8000); } //clear incoming modes m_dwIncomingModes = 0; //outgoing modes will be finalized during H.245 phase m_dwOutgoingModes = g_pH323Line->GetMediaModes() | LINEMEDIAMODE_UNKNOWN; //save media modes specified m_dwRequestedModes = g_pH323Line->GetMediaModes(); H323DBG(( DEBUG_LEVEL_TRACE, "InitializeIncomingCall exited:%p.", this )); return TRUE; cleanup: return FALSE; } //!!always called in a lock BOOL CH323Call::ChangeCallState( IN DWORD dwCallState, IN DWORD dwCallStateMode ) /*++ Routine Description: Reports call state of specified call object. Arguments: dwCallState - Specifies new state of call object. dwCallStateMode - Specifies new state mode of call object. Return Values: Returns true if successful. --*/ { H323DBG(( DEBUG_LEVEL_VERBOSE, "call 0x%08lx %s. state mode: 0x%08lx.", this, H323CallStateToString(dwCallState), dwCallStateMode )); // save new call state m_dwCallState = dwCallState; m_dwCallStateMode = dwCallStateMode; if( ((m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall ) || ((m_dwCallType & CALLTYPE_TRANSFEREDSRC ) && m_hdRelatedCall ) || (m_dwCallType & CALLTYPE_FORWARDCONSULT ) ) { return TRUE; } // report call status PostLineEvent ( LINE_CALLSTATE, m_dwCallState, m_dwCallStateMode, m_dwIncomingModes | m_dwOutgoingModes); // success return TRUE; } //always called in a lock void CH323Call::CopyU2UAsNonStandard( IN DWORD dwDirection ) { PUserToUserLE pU2ULE = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "CopyU2UAsNonStandard entered:%p.", this )); if( RemoveU2U( dwDirection, &pU2ULE ) ) { // transfer header information m_NonStandardData.bCountryCode = H221_COUNTRY_CODE_USA; m_NonStandardData.bExtension = H221_COUNTRY_EXT_USA; m_NonStandardData.wManufacturerCode = H221_MFG_CODE_MICROSOFT; // initialize octet string containing data m_NonStandardData.sData.wOctetStringLength = LOWORD(pU2ULE->dwU2USize); if( m_NonStandardData.sData.pOctetString ) { delete m_NonStandardData.sData.pOctetString; m_NonStandardData.sData.pOctetString = NULL; } //We are assigning here part of the structure and then may be the structure is deleted or not?? m_NonStandardData.sData.pOctetString = pU2ULE->pU2U; delete pU2ULE; } else { //reset non standard data memset( (PVOID)&m_NonStandardData,0,sizeof(H323NonStandardData )); } H323DBG(( DEBUG_LEVEL_TRACE, "CopyU2UAsNonStandard exited:%p.", this )); } void CH323Call::AcceptCall(void) /*++ Routine Description: Accepts incoming call. !!always called in lock Arguments: Return Values: Returns true if successful. --*/ { PH323_CALL pCall = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "AcceptCall entered:%p.", this )); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { return; } // see if user user information specified CopyU2UAsNonStandard( U2U_OUTBOUND ); if( m_pwszDisplay == NULL ) { // see if callee alias specified if( m_pCalleeAliasNames && m_pCalleeAliasNames -> wCount ) { if((m_pCalleeAliasNames->pItems[0].wType == h323_ID_chosen) || (m_pCalleeAliasNames ->pItems[0].wType == e164_chosen) ) { // send callee name as display m_pwszDisplay = m_pCalleeAliasNames -> pItems[0].pData; } } } //send answer call message to the MSP instance if( (m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall ) { MSPMessageData* pMSPMessageData = new MSPMessageData; if( pMSPMessageData == NULL ) { CloseCall( 0 ); return; } pMSPMessageData->hdCall = m_hdRelatedCall; pMSPMessageData->messageType = SP_MSG_AnswerCall; pMSPMessageData->pbEncodedBuf = NULL; pMSPMessageData->wLength = 0; pMSPMessageData->hReplacementCall = m_hdCall; if( !QueueUserWorkItem( SendMSPMessageOnRelatedCall, pMSPMessageData, WT_EXECUTEDEFAULT ) ) { delete pMSPMessageData; CloseCall( 0 ); return; } } else { SendMSPMessage( SP_MSG_AnswerCall, 0, 0, NULL ); } m_fCallAccepted = TRUE; if( m_fReadyToAnswer ) { // validate status if( !AcceptH323Call() ) { H323DBG(( DEBUG_LEVEL_ERROR, "error answering call 0x%08lx.", this )); // drop call using disconnect mode DropCall( LINEDISCONNECTMODE_TEMPFAILURE ); // failure return; } if( !(m_dwFlags & H245_START_MSG_SENT) ) { //start H245 SendMSPStartH245( NULL, NULL ); } //tell MSP about connect state SendMSPMessage( SP_MSG_ConnectComplete, 0, 0, NULL ); //change call state to accepted from offering ChangeCallState( LINECALLSTATE_CONNECTED, 0 ); } H323DBG(( DEBUG_LEVEL_TRACE, "AcceptCall exited:%p.", this )); // success return; } //always called in lock void CH323Call::ReleaseU2U(void) { PUserToUserLE pU2ULE = NULL; PLIST_ENTRY pLE; H323DBG(( DEBUG_LEVEL_TRACE, "ReleaseU2U entered:%p.", this )); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { return; } // see if list is empty if( IsListEmpty( &m_IncomingU2U ) == FALSE ) { // remove first entry from list pLE = RemoveHeadList( &m_IncomingU2U ); // convert to user user structure pU2ULE = CONTAINING_RECORD(pLE, UserToUserLE, Link); // release memory if(pU2ULE) { delete pU2ULE; pU2ULE = NULL; } } // see if list contains pending data if( IsListEmpty( &m_IncomingU2U ) == FALSE ) { H323DBG(( DEBUG_LEVEL_VERBOSE, "more user user info available." )); // signal incoming PostLineEvent ( LINE_CALLINFO, LINECALLINFOSTATE_USERUSERINFO, 0, 0); } H323DBG(( DEBUG_LEVEL_TRACE, "ReleaseU2U exited:%p.", this )); } //always called in lock void CH323Call::SendU2U( IN BYTE* pUserUserInfo, IN DWORD dwSize ) { H323DBG(( DEBUG_LEVEL_TRACE, "SendU2U entered:%p.", this )); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { return; } // check for user user info if( pUserUserInfo != NULL ) { // transfer header information m_NonStandardData.bCountryCode = H221_COUNTRY_CODE_USA; m_NonStandardData.bExtension = H221_COUNTRY_EXT_USA; m_NonStandardData.wManufacturerCode = H221_MFG_CODE_MICROSOFT; // initialize octet string containing data m_NonStandardData.sData.wOctetStringLength = (WORD)dwSize; if( m_NonStandardData.sData.pOctetString != NULL ) { delete m_NonStandardData.sData.pOctetString; m_NonStandardData.sData.pOctetString = NULL; } m_NonStandardData.sData.pOctetString = pUserUserInfo; } // send user user data if( !SendQ931Message( 0, 0, 0, FACILITYMESSAGETYPE, NO_H450_APDU ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "error sending non-standard message.")); } H323DBG(( DEBUG_LEVEL_TRACE, "SendU2U exited:%p.", this )); return; } BOOL CH323Call::InitializeQ931( IN SOCKET callSocket ) { BOOL fSuccess; H323DBG((DEBUG_LEVEL_ERROR, "q931 call initialize entered:%p.", this )); if( !BindIoCompletionCallback( (HANDLE)callSocket, CH323Call::IoCompletionCallback, 0) ) { H323DBG(( DEBUG_LEVEL_ERROR, "couldn't bind i/o completion callabck:%d:%p.", GetLastError(), this )); return FALSE; } //initilize the member variables m_callSocket = callSocket; H323DBG((DEBUG_LEVEL_ERROR, "q931 call initialize exited:%lx, %p.", m_callSocket, this )); return TRUE; } //no need to lock BOOL CH323Call::GetPeerAddress( IN H323_ADDR *pAddr ) { SOCKADDR_IN sockaddr; int len = sizeof(sockaddr); H323DBG((DEBUG_LEVEL_ERROR, "GetPeerAddress entered:%p.", this )); if( getpeername( m_callSocket, (SOCKADDR*)&sockaddr, &len) == SOCKET_ERROR ) { H323DBG(( DEBUG_LEVEL_ERROR, "error 0x%08lx calling getpeername.", WSAGetLastError() )); return FALSE; } pAddr->nAddrType = H323_IP_BINARY; pAddr->bMulticast = FALSE; pAddr->Addr.IP_Binary.wPort = ntohs(sockaddr.sin_port); pAddr->Addr.IP_Binary.dwAddr = ntohl(sockaddr.sin_addr.S_un.S_addr); H323DBG(( DEBUG_LEVEL_ERROR, "GetPeerAddress exited:%p.", this )); return TRUE; } //no need to lock BOOL CH323Call::GetHostAddress( IN H323_ADDR *pAddr ) { int len = sizeof(m_LocalAddr); H323DBG((DEBUG_LEVEL_ERROR, "GetHostAddress entered:%p.", this )); if( getsockname( m_callSocket, (SOCKADDR *)&m_LocalAddr, &len) == SOCKET_ERROR) { H323DBG(( DEBUG_LEVEL_ERROR, "error 0x%08lx calling getockname.", WSAGetLastError() )); return FALSE; } pAddr->nAddrType = H323_IP_BINARY; pAddr->bMulticast = FALSE; pAddr->Addr.IP_Binary.wPort = ntohs(m_LocalAddr.sin_port); pAddr->Addr.IP_Binary.dwAddr = ntohl(m_LocalAddr.sin_addr.S_un.S_addr); H323DBG((DEBUG_LEVEL_ERROR, "GetHostAddress exited:%p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::OnReceiveFacility( IN Q931MESSAGE* pMessage ) { Q931_FACILITY_ASN facilityASN; H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveFacility entered: %p.", this )); //decode the U2U information if( !pMessage ->UserToUser.fPresent || pMessage ->UserToUser.wUserInfoLen == 0 ) { //Ignore this message. Don't shutdown the call. return FALSE; } if( !ParseFacilityASN( pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, &facilityASN )) { //memory failure : shutdown the H323 call CloseCall( 0 ); return FALSE; } if( (facilityASN.pH245PDU.length != 0) && facilityASN.pH245PDU.value ) { SendMSPMessage( SP_MSG_H245PDU, facilityASN.pH245PDU.value, facilityASN.pH245PDU.length, NULL ); delete facilityASN.pH245PDU.value; } HandleFacilityMessage( facilityASN.dwInvokeID, &facilityASN ); H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveFacility exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::OnReceiveProceeding( IN Q931MESSAGE* pMessage ) { Q931_CALL_PROCEEDING_ASN proceedingASN; DWORD dwAPDUType = 0; H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveProceeding entered: %p.", this )); //decode the U2U information if( (pMessage ->UserToUser.fPresent == FALSE) || (pMessage ->UserToUser.wUserInfoLen == 0) ) { //ignore this message. don't shutdown the call. return FALSE; } if( (m_dwOrigin!=LINECALLORIGIN_OUTBOUND) || ( (m_dwStateMachine != Q931_SETUP_SENT) && (m_dwStateMachine != Q931_PROCEED_RECVD) ) ) { //ignore this message. don't shutdown the Q931 call. return FALSE; } if( !ParseProceedingASN( pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, &proceedingASN, &dwAPDUType )) { //Ignore the wrong proceeding message. H323DBG(( DEBUG_LEVEL_ERROR, "wrong proceeding PDU:%p.", this )); H323DUMPBUFFER( pMessage->UserToUser.pbUserInfo, (DWORD)pMessage->UserToUser.wUserInfoLen ); return TRUE; } if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //success of forwarding EnableCallForwarding(); CloseCall( 0 ); return TRUE; } HandleProceedingMessage( &proceedingASN ); //reset the timeout for setup sent if( m_hSetupSentTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hSetupSentTimer, NULL ); m_hSetupSentTimer = NULL; } H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveProceeding exited: %p.", this )); m_dwStateMachine = Q931_PROCEED_RECVD; return TRUE; } //!!always called in a lock BOOL CH323Call::OnReceiveAlerting( IN Q931MESSAGE* pMessage ) { Q931_ALERTING_ASN alertingASN; DWORD dwAPDUType = 0; H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveAlerting entered: %p.", this )); //decode the U2U information if( (pMessage ->UserToUser.fPresent == FALSE) || (pMessage ->UserToUser.wUserInfoLen == 0) ) { //ignore this message. don't shutdown the call. return FALSE; } if( (m_dwOrigin!=LINECALLORIGIN_OUTBOUND) || !( (m_dwStateMachine==Q931_SETUP_SENT) || (m_dwStateMachine==Q931_PROCEED_RECVD) ) ) { //ignore this message. don't shutdown the Q931 call. return FALSE; } if( !ParseAlertingASN( pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, &alertingASN, &dwAPDUType )) { //memory failure : shutdown the H323 call CloseCall( 0 ); return FALSE; } if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //success of forwarding EnableCallForwarding(); CloseCall( 0 ); return FALSE; } //reset the timeout for setup sent if( m_hSetupSentTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hSetupSentTimer, NULL ); m_hSetupSentTimer = NULL; } if( !CreateTimerQueueTimer( &m_hCallEstablishmentTimer, H323TimerQueue, CH323Call::CallEstablishmentExpiredCallback, (PVOID)m_hdCall, g_RegistrySettings.dwQ931AlertingTimeout, 0, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE )) { CloseCall( 0 ); return FALSE; } HandleAlertingMessage( &alertingASN ); m_dwStateMachine = Q931_ALERT_RECVD; H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveAlerting exited: %p.", this )); return TRUE; } //!!always called in lock void CH323Call::SetupSentTimerExpired(void) { DWORD dwState; H323DBG((DEBUG_LEVEL_TRACE, "SetupSentTimerExpired entered.")); dwState = m_dwStateMachine; if( m_hSetupSentTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hSetupSentTimer, NULL ); m_hSetupSentTimer = NULL; } if( (dwState!= Q931_CONNECT_RECVD) && (dwState != Q931_ALERT_RECVD) && (dwState != Q931_PROCEED_RECVD) && (dwState != Q931_RELEASE_RECVD) ) { //time out has occured CloseCall( 0 ); } H323DBG((DEBUG_LEVEL_TRACE, "SetupSentTimerExpired exited." )); } //!!always called in a lock BOOL CH323Call::OnReceiveRelease( IN Q931MESSAGE* pMessage ) { DWORD dwAPDUType = 0; Q931_RELEASE_COMPLETE_ASN releaseASN; //decode the U2U information if( (pMessage ->UserToUser.fPresent == FALSE) || (pMessage ->UserToUser.wUserInfoLen == 0) ) { H323DBG(( DEBUG_LEVEL_ERROR, "ReleaseComplete PDU did not contain " "user-to-user information, ignoring message." )); //ignore this message. don't shutdown the call. return FALSE; } if( !ParseReleaseCompleteASN( pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, &releaseASN, &dwAPDUType )) { H323DBG(( DEBUG_LEVEL_ERROR, "ReleaseComplete PDU could not be parsed, terminating call." )); //memory failure : shutdown the H323 call CloseCall( 0 ); return FALSE; } H323DBG ((DEBUG_LEVEL_INFO, "Received ReleaseComplete PDU.")); HandleReleaseMessage( &releaseASN ); m_dwStateMachine = Q931_RELEASE_RECVD; return TRUE; } //!!always called in a lock BOOL CH323Call::OnReceiveConnect( IN Q931MESSAGE* pMessage ) { Q931_CONNECT_ASN connectASN; DWORD dwH450APDUType = 0; H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveConnect entered: %p.", this )); //decode the U2U information if( (pMessage ->UserToUser.fPresent == FALSE) || (pMessage ->UserToUser.wUserInfoLen == 0) ) { //ignore this message. don't shutdown the call. return FALSE; } if( m_dwOrigin!=LINECALLORIGIN_OUTBOUND ) { //ignore this message. don't shutdown the Q931 call. return FALSE; } if( (m_dwStateMachine != Q931_SETUP_SENT) && (m_dwStateMachine != Q931_ALERT_RECVD) && (m_dwStateMachine != Q931_PROCEED_RECVD) ) { //ignore this message. don't shutdown the Q931 call. return FALSE; } if( ParseConnectASN( pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, &connectASN, &dwH450APDUType) == FALSE ) { //memory failure : shutdown the H323 call CloseCall( 0 ); return FALSE; } if( m_dwCallType & CALLTYPE_FORWARDCONSULT ) { FreeConnectASN( &connectASN ); if( dwH450APDUType == H4503_DUMMYTYPERETURNRESULT_APDU) { //assuming this return result is for check restriction operation return TRUE; } else { //success of forwarding EnableCallForwarding(); CloseCall( 0 ); return FALSE; } } if( !HandleConnectMessage( &connectASN ) ) { return FALSE; } //reset the timeout for setup sent if( m_hSetupSentTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hSetupSentTimer, NULL ); m_hSetupSentTimer = NULL; } if( m_hCallEstablishmentTimer ) { DeleteTimerQueueTimer(H323TimerQueue, m_hCallEstablishmentTimer, NULL); m_hCallEstablishmentTimer = NULL; } m_dwStateMachine = Q931_CONNECT_RECVD; H323DBG((DEBUG_LEVEL_TRACE, "OnReceiveConnect exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::OnReceiveSetup( IN Q931MESSAGE* pMessage ) { Q931_SETUP_ASN setupASN; DWORD dwH450APDUType = 0; PH323_CALL pCall = NULL; WCHAR pwszCallingPartyNr[H323_MAXPATHNAMELEN]; WCHAR pwszCalledPartyNr[H323_MAXPATHNAMELEN]; BYTE* pstrTemp; //decode the U2U information if( (pMessage ->UserToUser.fPresent == FALSE) || (pMessage ->UserToUser.wUserInfoLen == 0) ) { H323DBG(( DEBUG_LEVEL_ERROR, "Setup message did not contain H.323 UUIE, ignoring.")); //ignore this message. don't shutdown the call. return FALSE; } if( m_dwOrigin != LINECALLORIGIN_INBOUND ) { H323DBG(( DEBUG_LEVEL_ERROR, "Received Setup message on outbound call, ignoring.")); //ignore this message. don't shutdown the call. return FALSE; } if( m_dwStateMachine != Q931_CALL_STATE_NONE ) { H323DBG( (DEBUG_LEVEL_ERROR, "Received Setup message on a call that is already in progress." )); //This Q931 call has already received a setup!!!! CloseCall( 0 ); return FALSE; } if( !ParseSetupASN( pMessage->UserToUser.pbUserInfo, pMessage->UserToUser.wUserInfoLen, &setupASN, &dwH450APDUType )) { H323DBG(( DEBUG_LEVEL_ERROR, "Failed to parse Setup UUIE, closing call." )); //shutdown the Q931 call CloseCall( 0 ); return FALSE; } if( dwH450APDUType ) { if( m_dwCallType & CALLTYPE_FORWARDCONSULT ) { return TRUE; } } if( (pMessage->CallingPartyNumber.fPresent == TRUE) && (pMessage->CallingPartyNumber.dwLength > 1) && (setupASN.pCallerAliasList == 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) pstrTemp = pMessage->CallingPartyNumber.pbContents + ((pMessage->CallingPartyNumber.pbContents[1] & 0x80)? 2 : 1); MultiByteToWideChar( CP_ACP, 0, (const char *)(pstrTemp), -1, pwszCallingPartyNr, sizeof(pwszCallingPartyNr)/sizeof(WCHAR)); setupASN.pCallerAliasList = new H323_ALIASNAMES; if( setupASN.pCallerAliasList != NULL ) { ZeroMemory( setupASN.pCallerAliasList, sizeof(H323_ALIASNAMES) ); AddAliasItem( setupASN.pCallerAliasList, pwszCallingPartyNr, e164_chosen ); } } if( (pMessage->CalledPartyNumber.fPresent == TRUE) && (pMessage->CalledPartyNumber.PartyNumberLength > 0) && (setupASN.pCalleeAliasList == 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) MultiByteToWideChar(CP_ACP, 0, (const char *)(pMessage->CalledPartyNumber.PartyNumbers), -1, pwszCalledPartyNr, sizeof(pwszCalledPartyNr) / sizeof(WCHAR) ); setupASN.pCalleeAliasList = new H323_ALIASNAMES; if( setupASN.pCalleeAliasList != NULL ) { ZeroMemory( setupASN.pCalleeAliasList, sizeof(H323_ALIASNAMES) ); AddAliasItem( setupASN.pCalleeAliasList, pwszCalledPartyNr, e164_chosen ); } } //don't change the call type here if( !InitializeIncomingCall( &setupASN, m_dwCallType, pMessage->wCallRef ) ) { H323DBG ((DEBUG_LEVEL_ERROR, "Failed to initialize incoming call, closing call.")); //shutdown the Q931 call FreeSetupASN( &setupASN ); CloseCall( 0 ); return FALSE; } FreeSetupASN( &setupASN ); m_dwStateMachine = Q931_SETUP_RECVD; if( !HandleSetupMessage( pMessage ) ) { H323DBG ((DEBUG_LEVEL_ERROR, "Failed to process Setup message, closing call.")); CloseCall( 0 ); return FALSE; } return TRUE; } //!!always called in a lock void CH323Call::CloseCall( IN DWORD dwDisconnectMode ) { H323DBG((DEBUG_LEVEL_INFO, "[%08XH] Terminating call.", this )); if (!QueueTAPILineRequest( TSPI_CLOSE_CALL, m_hdCall, NULL, dwDisconnectMode, m_wCallReference )) { H323DBG(( DEBUG_LEVEL_ERROR, "could not post H323 close event." )); } } //!!always called in a lock void CH323Call::ReadEvent( IN DWORD cbTransfer ) { H323DBG((DEBUG_LEVEL_TRACE, "ReadEvent entered: %p.", this )); H323DBG((DEBUG_LEVEL_TRACE, "bytes received: %d.", cbTransfer)); m_RecvBuf.dwBytesCopied += cbTransfer; //update the recv buffer if( m_bStartOfPDU ) { if( m_RecvBuf.dwBytesCopied < sizeof(TPKT_HEADER_SIZE) ) { //set the buffer to get the remainig TPKT_HEADER m_RecvBuf.WSABuf.buf = m_RecvBuf.arBuf + m_RecvBuf.dwBytesCopied; m_RecvBuf.WSABuf.len = TPKT_HEADER_SIZE - m_RecvBuf.dwBytesCopied; } else { m_RecvBuf.dwPDULen = GetTpktLength( m_RecvBuf.arBuf ); if( (m_RecvBuf.dwPDULen < TPKT_HEADER_SIZE) || (m_RecvBuf.dwPDULen > Q931_RECV_BUFFER_LENGTH) ) { //messed up peer. close the call. H323DBG(( DEBUG_LEVEL_ERROR, "error:PDULen:%d.", m_RecvBuf.dwPDULen )); //close the call CloseCall( 0 ); return; } else if( m_RecvBuf.dwPDULen == TPKT_HEADER_SIZE ) { InitializeRecvBuf(); } else { //set the buffer to get the remaining PDU m_bStartOfPDU = FALSE; m_RecvBuf.WSABuf.buf = m_RecvBuf.arBuf + m_RecvBuf.dwBytesCopied; m_RecvBuf.WSABuf.len = m_RecvBuf.dwPDULen - m_RecvBuf.dwBytesCopied; } } } else { _ASSERTE( m_RecvBuf.dwBytesCopied <= m_RecvBuf.dwPDULen ); if( m_RecvBuf.dwBytesCopied == m_RecvBuf.dwPDULen ) { //we got the whole PDU if( !ProcessQ931PDU( &m_RecvBuf ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "error in processing PDU:%p.", this )); H323DUMPBUFFER( (BYTE*)m_RecvBuf.arBuf, m_RecvBuf.dwPDULen ); } //if the call has been already shutdown due to //a fatal error while processing the PDU or because of receiveing //release complete message then dont post any more read buffers if( (m_dwFlags & CALLOBJECT_SHUTDOWN) || (m_dwQ931Flags & Q931_CALL_DISCONNECTED) ) { return; } InitializeRecvBuf(); } else { //set the buffer to get the remainig PDU m_RecvBuf.WSABuf. buf = m_RecvBuf.arBuf + m_RecvBuf.dwBytesCopied; m_RecvBuf.WSABuf. len = m_RecvBuf.dwPDULen - m_RecvBuf.dwBytesCopied; } } //post a read for the remaining PDU if(!PostReadBuffer()) { //post a message to the callback thread to shutdown the H323 call CloseCall( 0 ); } H323DBG((DEBUG_LEVEL_TRACE, "ReadEvent exited: %p.", this )); } /* Parse a generic Q931 message and place the fields of the buffer into the appropriate structure fields. Parameters: pBuf Pointer to buffer descriptor of an input packet containing the 931 message. pMessage Pointer to space for parsed output information. */ //!!always called in a lock HRESULT CH323Call::Q931ParseMessage( IN BYTE * pbCodedBuffer, IN DWORD dwCodedBufferLength, OUT PQ931MESSAGE pMessage ) { HRESULT hr; BUFFERDESCR pBuf; pBuf.dwLength = dwCodedBufferLength; pBuf.pbBuffer = pbCodedBuffer; H323DBG((DEBUG_LEVEL_TRACE, "Q931ParseMessage entered: %p.", this )); memset( (PVOID)pMessage, 0, sizeof(Q931MESSAGE)); hr = ParseProtocolDiscriminator(&pBuf, &pMessage->ProtocolDiscriminator); if( hr != S_OK ) { return hr; } hr = ParseCallReference( &pBuf, &pMessage->wCallRef); if( hr != S_OK ) { return hr; } hr = ParseMessageType( &pBuf, &pMessage->MessageType ); if( hr != S_OK ) { return hr; } while (pBuf.dwLength) { hr = ParseQ931Field(&pBuf, pMessage); if (hr != S_OK) { return hr; } } H323DBG((DEBUG_LEVEL_TRACE, "Q931ParseMessage exited: %p.", this )); return S_OK; } //decode the PDU and release the buffer //!!always called in a lock BOOL CH323Call::ProcessQ931PDU( IN CALL_RECV_CONTEXT* pRecvBuf ) { PQ931MESSAGE pMessage; BOOL retVal; HRESULT hr; H323DBG((DEBUG_LEVEL_TRACE, "ProcessQ931PDU entered: %p.", this )); pMessage = new Q931MESSAGE; if( pMessage == NULL ) { return FALSE; } hr = Q931ParseMessage( (BYTE*)(pRecvBuf->arBuf + sizeof(TPKT_HEADER_SIZE)), pRecvBuf->dwPDULen - 4, pMessage ); if( !SUCCEEDED( hr) ) { delete pMessage; return FALSE; } if( (m_dwCallType & CALLTYPE_TRANSFERED_PRIMARY ) && (m_dwCallDiversionState == H4502_CTINITIATE_RECV) && (pMessage->MessageType != RELEASECOMPLMESSAGETYPE) ) { // If this endpoint has already been transferred then // ignore any further messages on the primary call. delete pMessage; return FALSE; } switch( pMessage->MessageType ) { case ALERTINGMESSAGETYPE: retVal = OnReceiveAlerting( pMessage ); break; case PROCEEDINGMESSAGETYPE: retVal = OnReceiveProceeding( pMessage ); break; case CONNECTMESSAGETYPE: retVal = OnReceiveConnect( pMessage ); break; case RELEASECOMPLMESSAGETYPE: retVal = OnReceiveRelease( pMessage ); break; case SETUPMESSAGETYPE: retVal = OnReceiveSetup( pMessage ); break; case FACILITYMESSAGETYPE: retVal = OnReceiveFacility( pMessage ); break; default: H323DBG(( DEBUG_LEVEL_TRACE, "unrecognised PDU recvd:%d,%p.", pMessage->MessageType, this )); retVal = FALSE; } delete pMessage; H323DBG((DEBUG_LEVEL_TRACE, "ProcessQ931PDU exited: %p.", this )); return retVal; } //!!always called in a lock void CH323Call::OnConnectComplete(void) { BOOL fSuccess = TRUE; PH323_CALL pCall = NULL; H323DBG((DEBUG_LEVEL_TRACE, "OnConnectComplete entered: %p.", this )); _ASSERTE( m_dwOrigin==LINECALLORIGIN_OUTBOUND ); if( !GetHostAddress( &m_CallerAddr) ) { //memory failure : shutdown the H323 call CloseCall( 0 ); return; } InitializeRecvBuf(); //post a buffer to winsock to accept messages from the peer if( !PostReadBuffer() ) { //memory failure : shutdown the H323 call CloseCall( 0 ); return; } //set the state to connected SetQ931CallState( Q931_CALL_CONNECTED ); if( (m_dwCallType == CALLTYPE_NORMAL) || (m_dwCallType & CALLTYPE_TRANSFERING_CONSULT) ) { SendMSPMessage( SP_MSG_InitiateCall, 0, 0, NULL ); } else if( m_dwCallType & CALLTYPE_TRANSFEREDSRC ) { _ASSERTE( m_hdRelatedCall ); MSPMessageData* pMSPMessageData = new MSPMessageData; if( pMSPMessageData == NULL ) { CloseCall( 0 ); return; } pMSPMessageData->hdCall = m_hdRelatedCall; pMSPMessageData->messageType = SP_MSG_InitiateCall; pMSPMessageData->pbEncodedBuf = NULL; pMSPMessageData->wLength = 0; pMSPMessageData->hReplacementCall = m_hdCall; if( !QueueUserWorkItem( SendMSPMessageOnRelatedCall, pMSPMessageData, WT_EXECUTEDEFAULT ) ) { delete pMSPMessageData; CloseCall( 0 ); return; } } else { //send the setup message if( !SendSetupMessage() ) { DropCall( 0 ); } } H323DBG((DEBUG_LEVEL_TRACE, "OnConnectComplete exited: %p.", this )); } //!!aleways called in a lock BOOL CH323Call::SendSetupMessage(void) { BOOL retVal = TRUE; DWORD dwAPDUType = NO_H450_APDU; H323DBG((DEBUG_LEVEL_TRACE, "SendSetupMessage entered: %p.", this )); //encode ASN.1 and send Q931Setup message to the peer if( m_dwCallType & CALLTYPE_FORWARDCONSULT ) { //send the callRerouitng.invoke APDU if this is a forwardconsult call retVal = SendQ931Message( NO_INVOKEID, (DWORD)create_chosen, (DWORD)pointToPoint_chosen, SETUPMESSAGETYPE, CHECKRESTRICTION_OPCODE| H450_INVOKE ); if( retVal ) { m_dwStateMachine = Q931_SETUP_SENT; m_dwCallDiversionState = H4503_CHECKRESTRICTION_SENT; retVal = CreateTimerQueueTimer( &m_hCheckRestrictionTimer, H323TimerQueue, CH323Call::CheckRestrictionTimerCallback, (PVOID)m_hdCall, CHECKRESTRICTION_EXPIRE_TIME, 0, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ); } } else { if( ( m_dwCallType & CALLTYPE_DIVERTEDSRC ) || ( m_dwCallType & CALLTYPE_DIVERTEDSRC_NOROUTING ) ) { dwAPDUType = DIVERTINGLEGINFO2_OPCODE | H450_INVOKE; } else if( m_dwCallType & CALLTYPE_TRANSFEREDSRC ) { dwAPDUType = CTSETUP_OPCODE | H450_INVOKE; } retVal = SendQ931Message( NO_INVOKEID, (DWORD)create_chosen, (DWORD)pointToPoint_chosen, SETUPMESSAGETYPE, dwAPDUType ); if( retVal ) { m_dwStateMachine = Q931_SETUP_SENT; retVal = CreateTimerQueueTimer( &m_hSetupSentTimer, H323TimerQueue, CH323Call::SetupSentTimerCallback, (PVOID)m_hdCall, SETUP_SENT_TIMEOUT, 0, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ); } } if( retVal == FALSE ) { CloseCall( 0 ); return FALSE; } H323DBG((DEBUG_LEVEL_TRACE, "SendSetupMessage exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::SendProceeding(void) { H323DBG((DEBUG_LEVEL_TRACE, "SendProceeding entered: %p.", this )); _ASSERTE( m_dwOrigin == LINECALLORIGIN_INBOUND ); //encode ASN.1 and send Q931Setup message to the peer if(!SendQ931Message( NO_INVOKEID, 0, 0, PROCEEDINGMESSAGETYPE, NO_H450_APDU )) { return FALSE; } m_dwStateMachine = Q931_PROCEED_SENT; H323DBG((DEBUG_LEVEL_TRACE, "SendProceeding exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::PostReadBuffer(void) { int iError; DWORD dwByteReceived = 0; BOOL fDelete = FALSE; H323DBG((DEBUG_LEVEL_TRACE, "PostReadBuffer entered: %p.", this )); m_RecvBuf.Type = OVERLAPPED_TYPE_RECV; m_RecvBuf.pCall = this; m_RecvBuf.dwFlags = 0; m_RecvBuf.BytesTransferred = 0; ZeroMemory( (PVOID)&m_RecvBuf.Overlapped, sizeof(OVERLAPPED) ); //register with winsock for overlappped I/O if( WSARecv( m_callSocket, &(m_RecvBuf.WSABuf), 1, &(m_RecvBuf.BytesTransferred), &(m_RecvBuf.dwFlags), &(m_RecvBuf.Overlapped), NULL ) == SOCKET_ERROR ) { iError = WSAGetLastError(); if( iError != WSA_IO_PENDING ) { //take care of error conditions here H323DBG((DEBUG_LEVEL_ERROR, "error while recving buf: %d.", iError )); return FALSE; } } else { //There is some data to read!!!!! H323DBG(( DEBUG_LEVEL_TRACE, "bytes received immediately: %d.", m_RecvBuf.BytesTransferred )); } m_IoRefCount++; H323DBG((DEBUG_LEVEL_TRACE, "PostReadBuffer:m_IoRefCount: %d:%p.", m_IoRefCount, this )); H323DBG((DEBUG_LEVEL_TRACE, "PostReadBuffer exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::SendBuffer( IN BYTE* pbBuffer, IN DWORD dwLength ) { int iError; CALL_SEND_CONTEXT* pSendBuf = NULL; DWORD cbTransfer; BOOL fDelete = FALSE; H323DBG((DEBUG_LEVEL_TRACE, "SendBuffer entered: %p.", this )); if( !(m_dwQ931Flags & Q931_CALL_CONNECTED) ) { goto cleanup; } pSendBuf = new CALL_SEND_CONTEXT; if( pSendBuf == NULL ) { goto cleanup; } ZeroMemory( (PVOID)pSendBuf, sizeof(CALL_SEND_CONTEXT) ); pSendBuf->WSABuf.buf = (char*)pbBuffer; pSendBuf->WSABuf.len = dwLength; pSendBuf->BytesTransferred = 0; pSendBuf->pCall = this; pSendBuf->Type = OVERLAPPED_TYPE_SEND; InsertTailList( &m_sendBufList, &(pSendBuf ->ListEntry) ); if( WSASend(m_callSocket, &(pSendBuf->WSABuf), 1, &(pSendBuf->BytesTransferred), 0, &(pSendBuf->Overlapped), NULL) == SOCKET_ERROR ) { iError = WSAGetLastError(); if( iError != WSA_IO_PENDING ) { H323DBG((DEBUG_LEVEL_TRACE, "error sending the buf: %lx.", iError)); RemoveEntryList( &pSendBuf->ListEntry ); goto cleanup; } } else { //data was sent immediately!!! H323DBG((DEBUG_LEVEL_TRACE, "data sent immediately!!." )); } m_IoRefCount++; H323DBG((DEBUG_LEVEL_TRACE, "SendBuffer:m_IoRefCount11: %d:%p.", m_IoRefCount, this )); H323DBG((DEBUG_LEVEL_TRACE, "SendBuffer exited: %p.", this )); return TRUE; cleanup: if(pSendBuf) { delete pSendBuf; } delete pbBuffer; return FALSE; } //!!aleways called in a lock BOOL CH323Call::SetupCall(void) { SOCKET Q931CallSocket = INVALID_SOCKET; SOCKADDR_IN sin; HANDLE hWSAEvent; HANDLE hConnWait; BOOL fSuccess = TRUE; int iError; BOOL fDelete; DWORD dwEnable = 1; TCHAR ptstrEventName[100]; H323DBG((DEBUG_LEVEL_TRACE, "SetupCall entered.")); //create a socket Q931CallSocket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, NULL, WSA_FLAG_OVERLAPPED ); if( Q931CallSocket == INVALID_SOCKET ) { H323DBG((DEBUG_LEVEL_ERROR, "error while creating socket: %lx.", WSAGetLastError() )); goto error1; } //create a new Q931 call object if( InitializeQ931(Q931CallSocket) == NULL ) { goto error2; } _stprintf( ptstrEventName, _T("%s-%p") , _T( "H323TSP_OutgoingCall_TransportHandlerEvent" ), this ); //create the wait event hWSAEvent = H323CreateEvent( NULL, FALSE, FALSE, ptstrEventName ); if( hWSAEvent == NULL ) { H323DBG((DEBUG_LEVEL_ERROR, "couldn't create wsaevent" )); goto error3; } //register with thread pool the event handle and handler proc fSuccess = RegisterWaitForSingleObject( &hConnWait, // pointer to the returned handle hWSAEvent, // the event handle to wait for. Q931TransportEventHandler, // the callback function. (PVOID)m_hdCall, // the context for the callback. INFINITE, // wait forever. // probably don't need this flag set WT_EXECUTEDEFAULT // use the wait thread to call the callback. ); if ( ( !fSuccess ) || (hConnWait== NULL) ) { GetLastError(); if( !CloseHandle( hWSAEvent ) ) { H323DBG((DEBUG_LEVEL_ERROR, "couldn't close wsaevent" )); } goto error3; } //store this in the call context SetNewCallInfo( hConnWait, hWSAEvent, Q931_CALL_CONNECTING ); //register with Winsock the event handle and the events if( WSAEventSelect( Q931CallSocket, hWSAEvent, FD_CONNECT | FD_CLOSE ) == SOCKET_ERROR ) { H323DBG((DEBUG_LEVEL_ERROR, "error selecting event outgoing call: %lx.", WSAGetLastError())); goto error3; } if( setsockopt( Q931CallSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&dwEnable, sizeof(DWORD) ) == SOCKET_ERROR ) { H323DBG(( DEBUG_LEVEL_WARNING, "Couldn't set NODELAY option on outgoing call socket:%d, %p", WSAGetLastError(), this )); } //set the address structure memset( (PVOID)&sin, 0, sizeof(SOCKADDR_IN) ); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl( m_CalleeAddr.Addr.IP_Binary.dwAddr ); sin.sin_port = htons( m_CalleeAddr.Addr.IP_Binary.wPort ); //make the winsock connection if( WSAConnect( Q931CallSocket, (sockaddr*)&sin, sizeof(SOCKADDR_IN), NULL, NULL, NULL, NULL ) == SOCKET_ERROR ) { iError = WSAGetLastError(); if(iError != WSAEWOULDBLOCK ) { H323DBG(( DEBUG_LEVEL_ERROR, "error while connecting socket: %lx.", iError )); goto error3; } } else { //connection went through immediately!!! OnConnectComplete(); } //success H323DBG((DEBUG_LEVEL_TRACE, "SetupCall exited.")); return TRUE; error3: Unlock(); Shutdown( &fDelete ); Lock(); error2: closesocket( Q931CallSocket ); error1: return FALSE; } //!!aleways called in a lock BOOL CH323Call::AcceptH323Call(void) { DWORD dwAPDUType = NO_H450_APDU; DWORD dwInvokeID = NO_INVOKEID; H323DBG((DEBUG_LEVEL_TRACE, "AcceptH323Call entered: %p.", this )); if( m_dwCallType & CALLTYPE_DIVERTEDDEST ) { dwAPDUType = (DIVERTINGLEGINFO3_OPCODE | H450_INVOKE); } else if( m_dwCallType & CALLTYPE_TRANSFEREDDEST ) { dwAPDUType = (CTSETUP_OPCODE | H450_RETURNRESULT); dwInvokeID = m_dwInvokeID; } ChangeCallState( LINECALLSTATE_ACCEPTED, 0 ); //if pCall Divert On No Answer is enabled, then stop the timer if( m_hCallDivertOnNATimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCallDivertOnNATimer, NULL ); m_hCallDivertOnNATimer = NULL; } //encode and send Q931Connect message to the peer if( !SendQ931Message( dwInvokeID, 0, 0, CONNECTMESSAGETYPE, dwAPDUType ) ) { //post a message to the callback thread to shutdown the H323 call CloseCall( 0 ); return FALSE; } m_dwStateMachine = Q931_CONNECT_SENT; H323DBG((DEBUG_LEVEL_TRACE, "AcceptH323Call exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::SendQ931Message( IN DWORD dwInvokeID, IN ULONG_PTR dwParam1, IN ULONG_PTR dwParam2, IN DWORD dwMessageType, IN DWORD dwAPDUType ) { BINARY_STRING userUserData; DWORD dwCodedLengthPDU; BYTE *pbCodedPDU; BOOL retVal = FALSE; WCHAR * pwszCalledPartyNumber = NULL; H323DBG((DEBUG_LEVEL_TRACE, "SendQ931Message entered: %p.", this )); //check if socket is connected if( !(m_dwQ931Flags & Q931_CALL_CONNECTED) ) { return FALSE; } switch ( dwMessageType ) { //encode the UU message case SETUPMESSAGETYPE: retVal = EncodeSetupMessage( dwInvokeID, (WORD)dwParam1, //dwGoal (WORD)dwParam2, //dwCalType &userUserData.pbBuffer, &userUserData.length, dwAPDUType ); break; case ALERTINGMESSAGETYPE: retVal = EncodeAlertMessage( dwInvokeID, &userUserData.pbBuffer, &userUserData.length, dwAPDUType ); break; case PROCEEDINGMESSAGETYPE: retVal = EncodeProceedingMessage( dwInvokeID, &userUserData.pbBuffer, &userUserData.length, dwAPDUType ); break; case RELEASECOMPLMESSAGETYPE: retVal = EncodeReleaseCompleteMessage( dwInvokeID, (BYTE*)dwParam1, //pbReason &userUserData.pbBuffer, &userUserData.length, dwAPDUType ); break; case CONNECTMESSAGETYPE: retVal = EncodeConnectMessage( dwInvokeID, &userUserData.pbBuffer, &userUserData.length, dwAPDUType ); break; case FACILITYMESSAGETYPE: retVal = EncodeFacilityMessage( dwInvokeID, (BYTE)dwParam1, (ASN1octetstring_t*)dwParam2, &userUserData.pbBuffer, &userUserData.length, dwAPDUType ); break; } if( retVal == FALSE ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not encode message:%d.", dwMessageType)); if( userUserData.pbBuffer ) { ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, userUserData.pbBuffer ); } return FALSE; } if (m_dwAddressType == LINEADDRESSTYPE_PHONENUMBER) { _ASSERTE( m_pCalleeAliasNames->pItems[0].wType == e164_chosen ); pwszCalledPartyNumber = m_pCalleeAliasNames ->pItems[0].pData; } //encode the PDU retVal = EncodePDU( &userUserData, &pbCodedPDU, &dwCodedLengthPDU, dwMessageType, pwszCalledPartyNumber ); if( retVal == FALSE ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not encode PDU: %d.", dwMessageType )); } else if(!SendBuffer( pbCodedPDU, dwCodedLengthPDU )) { retVal = FALSE; } if( userUserData.pbBuffer ) { ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, userUserData.pbBuffer ); } H323DBG((DEBUG_LEVEL_TRACE, "SendQ931Message exited: %p.", this )); return retVal; } //!!always called in a lock BOOL CH323Call::EncodeFastStartProposal( PH323_FASTSTART pFastStart, BYTE** ppEncodedBuf, WORD* pwEncodedLength ) { int rc; H323_UserInformation UserInfo; H323DBG((DEBUG_LEVEL_TRACE, "EncodeFastStartProposal entered: %p.", this )); CallProceeding_UUIE & proceedingMessage = UserInfo.h323_uu_pdu.h323_message_body.u.callProceeding; *ppEncodedBuf = NULL; *pwEncodedLength = 0; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; //copy the call identifier proceedingMessage.bit_mask |= CallProceeding_UUIE_callIdentifier_present; CopyMemory( (PVOID)&proceedingMessage.callIdentifier.guid.value, (PVOID)&m_callIdentifier, sizeof(GUID) ); proceedingMessage.callIdentifier.guid.length = sizeof(GUID); // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; UserInfo.h323_uu_pdu.h323_message_body.choice = callProceeding_chosen; proceedingMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; proceedingMessage.bit_mask |= CallProceeding_UUIE_fastStart_present; proceedingMessage.fastStart = (PCallProceeding_UUIE_fastStart)pFastStart; rc = EncodeASN( (void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pwEncodedLength); if (ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pwEncodedLength == 0) ) { return FALSE; } H323DBG((DEBUG_LEVEL_TRACE, "EncodeFastStartProposal exited: %p.", this )); //success return TRUE; } //!!always called in a lock BOOL CH323Call::EncodeFacilityMessage( IN DWORD dwInvokeID, IN BYTE bReason, IN ASN1octetstring_t* pH245PDU, OUT BYTE **ppEncodedBuf, OUT WORD *pdwEncodedLength, IN DWORD dwAPDUType ) { H323_UU_PDU_h4501SupplementaryService h4501APDU; int rc; H323_UserInformation UserInfo; DWORD dwAPDULen = 0; BYTE* pEncodedAPDU = NULL; H323DBG((DEBUG_LEVEL_TRACE, "EncodeFacilityMessage entered: %p.", this )); Facility_UUIE & facilityMessage = UserInfo.h323_uu_pdu.h323_message_body.u.facility; *ppEncodedBuf = NULL; *pdwEncodedLength = 0; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; //send the appropriate ADPDUS if( dwAPDUType != NO_H450_APDU ) { if( !EncodeH450APDU(dwInvokeID, dwAPDUType, &pEncodedAPDU, &dwAPDULen ) ) { return FALSE; } UserInfo.h323_uu_pdu.h4501SupplementaryService = &h4501APDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> next = NULL; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.value = pEncodedAPDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.length = dwAPDULen; UserInfo.h323_uu_pdu.bit_mask |= h4501SupplementaryService_present; } UserInfo.h323_uu_pdu.h245Tunneling = FALSE;//(m_fh245Tunneling & LOCAL_H245_TUNNELING); UserInfo.h323_uu_pdu.bit_mask |= h245Tunneling_present; SetNonStandardData( UserInfo ); UserInfo.h323_uu_pdu.h323_message_body.choice = facility_chosen; facilityMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; facilityMessage.bit_mask = 0; TransportAddress& transportAddress = facilityMessage.alternativeAddress; if( IsGuidSet( &m_ConferenceID ) ) { CopyConferenceID(&facilityMessage.conferenceID, &m_ConferenceID); facilityMessage.bit_mask |= Facility_UUIE_conferenceID_present; } switch (bReason) { case H323_REJECT_ROUTE_TO_GATEKEEPER: facilityMessage.reason.choice = FacilityReason_routeCallToGatekeeper_chosen; break; case H323_REJECT_CALL_FORWARDED: facilityMessage.reason.choice = callForwarded_chosen; break; case H323_REJECT_ROUTE_TO_MC: facilityMessage.reason.choice = routeCallToMC_chosen; break; default: facilityMessage.reason.choice = FacilityReason_undefinedReason_chosen; } facilityMessage.bit_mask |= Facility_UUIE_callIdentifier_present; CopyMemory( (PVOID)&facilityMessage.callIdentifier.guid.value, (PVOID)"abcdabcdabcdabcdabcd", sizeof(GUID) ); facilityMessage.callIdentifier.guid.length = sizeof(GUID); if( pH245PDU && (pH245PDU->value != NULL) ) { //h245 PDU to be sent UserInfo.h323_uu_pdu.h245Control->next = NULL; UserInfo.h323_uu_pdu.h245Control->value.length = pH245PDU->length; UserInfo.h323_uu_pdu.h245Control->value.value = pH245PDU->value; } rc = EncodeASN((void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pdwEncodedLength); if( ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pdwEncodedLength == 0) ) { if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } return FALSE; } if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } H323DBG((DEBUG_LEVEL_TRACE, "EncodeFacilityMessage exited: %p.", this )); //success return TRUE; } //!!always called in a lock BOOL CH323Call::EncodeAlertMessage( IN DWORD dwInvokeID, OUT BYTE **ppEncodedBuf, OUT WORD *pdwEncodedLength, IN DWORD dwAPDUType ) { H323_UU_PDU_h4501SupplementaryService h4501APDU; int rc; H323_UserInformation UserInfo; DWORD dwAPDULen = 0; BYTE* pEncodedAPDU = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeAlertMessage entered: %p.", this )); Alerting_UUIE & alertingMessage = UserInfo.h323_uu_pdu.h323_message_body.u.alerting; *ppEncodedBuf = NULL; *pdwEncodedLength = 0; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; if( dwAPDUType != NO_H450_APDU ) { if( !EncodeH450APDU( dwInvokeID, dwAPDUType, &pEncodedAPDU, &dwAPDULen ) ) { return FALSE; } UserInfo.h323_uu_pdu.h4501SupplementaryService = &h4501APDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> next = NULL; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.value = pEncodedAPDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.length = dwAPDULen; UserInfo.h323_uu_pdu.bit_mask |= h4501SupplementaryService_present; } UserInfo.h323_uu_pdu.h245Tunneling = FALSE;//(m_fh245Tunneling & LOCAL_H245_TUNNELING); UserInfo.h323_uu_pdu.bit_mask |= h245Tunneling_present; SetNonStandardData( UserInfo ); UserInfo.h323_uu_pdu.h323_message_body.choice = alerting_chosen; alertingMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; alertingMessage.destinationInfo.bit_mask = 0; //copy the vendor info alertingMessage.destinationInfo.bit_mask |= vendor_present; CopyVendorInfo( &alertingMessage.destinationInfo.vendor ); //its a terminal alertingMessage.destinationInfo.bit_mask = terminal_present; alertingMessage.destinationInfo.terminal.bit_mask = 0; //not na MC alertingMessage.destinationInfo.mc = 0; alertingMessage.destinationInfo.undefinedNode = 0; TransportAddress& transportAddress = alertingMessage.h245Address; //send H245 address only if the caller hasn't proposed FasrStart //or the fast start proposal has been accepeted if( (m_pPeerFastStart == NULL) || m_pFastStart ) { if( m_selfH245Addr.Addr.IP_Binary.dwAddr != 0 ) { CopyTransportAddress( transportAddress, &m_selfH245Addr ); alertingMessage.bit_mask |= (Alerting_UUIE_h245Address_present); } else { alertingMessage.bit_mask &= (~Alerting_UUIE_h245Address_present); } } if( m_pFastStart != NULL ) { _ASSERTE( m_pPeerFastStart ); alertingMessage.bit_mask |= Alerting_UUIE_fastStart_present; alertingMessage.fastStart = (PAlerting_UUIE_fastStart)m_pFastStart; } else { alertingMessage.bit_mask &= ~Alerting_UUIE_fastStart_present; } //copy the call identifier alertingMessage.bit_mask |= Alerting_UUIE_callIdentifier_present; CopyMemory( (PVOID)&alertingMessage.callIdentifier.guid.value, (PVOID)&m_callIdentifier, sizeof(GUID) ); alertingMessage.callIdentifier.guid.length = sizeof(GUID); rc = EncodeASN( (void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pdwEncodedLength); if (ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pdwEncodedLength == 0) ) { if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } return FALSE; } if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } H323DBG((DEBUG_LEVEL_TRACE, "EncodeAlertMessage exited: %p.", this )); //success return TRUE; } //!!always called in a lock BOOL CH323Call::EncodeProceedingMessage( IN DWORD dwInvokeID, OUT BYTE **ppEncodedBuf, OUT WORD *pdwEncodedLength, IN DWORD dwAPDUType ) { H323_UU_PDU_h4501SupplementaryService h4501APDU; int rc; H323_UserInformation UserInfo; DWORD dwAPDULen = 0; BYTE* pEncodedAPDU = NULL; H323DBG((DEBUG_LEVEL_TRACE, "EncodeProceedingMessage entered: %p.", this )); CallProceeding_UUIE & proceedingMessage = UserInfo.h323_uu_pdu.h323_message_body.u.callProceeding; *ppEncodedBuf = NULL; *pdwEncodedLength = 0; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; if( dwAPDUType != NO_H450_APDU ) { if( !EncodeH450APDU( dwInvokeID, dwAPDUType, &pEncodedAPDU, &dwAPDULen ) ) { return FALSE; } UserInfo.h323_uu_pdu.h4501SupplementaryService = &h4501APDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> next = NULL; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.value = pEncodedAPDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.length = dwAPDULen; UserInfo.h323_uu_pdu.bit_mask |= h4501SupplementaryService_present; } UserInfo.h323_uu_pdu.h245Tunneling = FALSE;//(m_fh245Tunneling & LOCAL_H245_TUNNELING); UserInfo.h323_uu_pdu.bit_mask |= h245Tunneling_present; SetNonStandardData( UserInfo ); UserInfo.h323_uu_pdu.h323_message_body.choice = callProceeding_chosen; proceedingMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; TransportAddress& transportAddress = proceedingMessage.h245Address; //send H245 address only if the caller hasn't proposed FasrStart //or the fast start proposal has been accepeted if( (m_pPeerFastStart == NULL) || m_pFastStart ) { if( m_selfH245Addr.Addr.IP_Binary.dwAddr != 0 ) { CopyTransportAddress( transportAddress, &m_selfH245Addr ); proceedingMessage.bit_mask |= CallProceeding_UUIE_h245Address_present; } else { proceedingMessage.bit_mask &= ~CallProceeding_UUIE_h245Address_present; } } proceedingMessage.destinationInfo.bit_mask = 0; //copy the vendor info proceedingMessage.destinationInfo.bit_mask |= vendor_present; CopyVendorInfo( &proceedingMessage.destinationInfo.vendor ); proceedingMessage.destinationInfo.mc = 0; proceedingMessage.destinationInfo.undefinedNode = 0; if( m_pFastStart != NULL ) { _ASSERTE( m_pPeerFastStart ); proceedingMessage.bit_mask |= Alerting_UUIE_fastStart_present; proceedingMessage.fastStart = (PCallProceeding_UUIE_fastStart)m_pFastStart; } else { proceedingMessage.bit_mask &= ~Alerting_UUIE_fastStart_present; } //copy the call identifier proceedingMessage.bit_mask |= CallProceeding_UUIE_callIdentifier_present; CopyMemory( (PVOID)&proceedingMessage.callIdentifier.guid.value, (PVOID)&m_callIdentifier, sizeof(GUID) ); proceedingMessage.callIdentifier.guid.length = sizeof(GUID); rc = EncodeASN( (void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pdwEncodedLength); if (ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pdwEncodedLength == 0) ) { if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } return FALSE; } if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } H323DBG((DEBUG_LEVEL_TRACE, "EncodeProceedingMessage exited: %p.", this )); //success return TRUE; } //!!always called in a lock BOOL CH323Call::EncodeReleaseCompleteMessage( IN DWORD dwInvokeID, IN BYTE *pbReason, OUT BYTE **ppEncodedBuf, OUT WORD *pdwEncodedLength, IN DWORD dwAPDUType ) { H323_UU_PDU_h4501SupplementaryService h4501APDU; int rc; H323_UserInformation UserInfo; DWORD dwAPDULen = 0; BYTE* pEncodedAPDU = NULL; H323DBG((DEBUG_LEVEL_TRACE, "EncodeReleaseCompleteMessage entered: %p.", this )); ReleaseComplete_UUIE & releaseMessage = UserInfo.h323_uu_pdu.h323_message_body.u.releaseComplete; *ppEncodedBuf = NULL; *pdwEncodedLength = 0; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; if( dwAPDUType != NO_H450_APDU ) { if( !EncodeH450APDU( dwInvokeID, dwAPDUType, &pEncodedAPDU, &dwAPDULen ) ) { return FALSE; } UserInfo.h323_uu_pdu.h4501SupplementaryService = &h4501APDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> next = NULL; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.value = pEncodedAPDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.length = dwAPDULen; UserInfo.h323_uu_pdu.bit_mask |= h4501SupplementaryService_present; } SetNonStandardData( UserInfo ); UserInfo.h323_uu_pdu.h323_message_body.choice = releaseComplete_chosen; releaseMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; if( pbReason ) { releaseMessage.reason.choice = 0; releaseMessage.bit_mask |= (ReleaseComplete_UUIE_reason_present); switch (*pbReason) { case H323_REJECT_NO_BANDWIDTH: releaseMessage.reason.choice = noBandwidth_chosen; break; case H323_REJECT_GATEKEEPER_RESOURCES: releaseMessage.reason.choice = gatekeeperResources_chosen; break; case H323_REJECT_UNREACHABLE_DESTINATION: releaseMessage.reason.choice = unreachableDestination_chosen; break; case H323_REJECT_DESTINATION_REJECTION: releaseMessage.reason.choice = destinationRejection_chosen; break; case H323_REJECT_INVALID_REVISION: releaseMessage.reason.choice = ReleaseCompleteReason_invalidRevision_chosen; break; case H323_REJECT_NO_PERMISSION: releaseMessage.reason.choice = noPermission_chosen; break; case H323_REJECT_UNREACHABLE_GATEKEEPER: releaseMessage.reason.choice = unreachableGatekeeper_chosen; break; case H323_REJECT_GATEWAY_RESOURCES: releaseMessage.reason.choice = gatewayResources_chosen; break; case H323_REJECT_BAD_FORMAT_ADDRESS: releaseMessage.reason.choice = badFormatAddress_chosen; break; case H323_REJECT_ADAPTIVE_BUSY: releaseMessage.reason.choice = adaptiveBusy_chosen; break; case H323_REJECT_IN_CONF: releaseMessage.reason.choice = inConf_chosen; break; case H323_REJECT_CALL_DEFLECTION: releaseMessage.reason.choice = ReleaseCompleteReason_undefinedReason_chosen ; break; case H323_REJECT_UNDEFINED_REASON: releaseMessage.reason.choice = ReleaseCompleteReason_undefinedReason_chosen ; break; case H323_REJECT_USER_BUSY: releaseMessage.reason.choice = inConf_chosen; break; default: //log if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } return FALSE; } } rc = EncodeASN( (void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pdwEncodedLength); if (ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pdwEncodedLength == 0) ) { if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } return FALSE; } if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } H323DBG((DEBUG_LEVEL_TRACE, "EncodeReleaseCompleteMessage exited: %p.", this )); //success return TRUE; } //!!always called in a lock BOOL CH323Call::EncodeConnectMessage( IN DWORD dwInvokeID, OUT BYTE **ppEncodedBuf, OUT WORD *pdwEncodedLength, IN DWORD dwAPDUType ) { H323_UU_PDU_h4501SupplementaryService h4501APDU; int rc; H323_UserInformation UserInfo; DWORD dwAPDULen = 0; BYTE* pEncodedAPDU = NULL; H323DBG((DEBUG_LEVEL_TRACE, "EncodeConnectMessage entered: %p.", this )); Connect_UUIE & connectMessage = UserInfo.h323_uu_pdu.h323_message_body.u.connect; *ppEncodedBuf = NULL; *pdwEncodedLength = 0; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; //send the appropriate ADPDUS if( dwAPDUType != NO_H450_APDU ) { if( !EncodeH450APDU( dwInvokeID, dwAPDUType, &pEncodedAPDU, &dwAPDULen ) ) { return FALSE; } UserInfo.h323_uu_pdu.h4501SupplementaryService = &h4501APDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> next = NULL; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.value = pEncodedAPDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.length = dwAPDULen; UserInfo.h323_uu_pdu.bit_mask |= h4501SupplementaryService_present; } UserInfo.h323_uu_pdu.h245Tunneling = FALSE;//(m_fh245Tunneling & LOCAL_H245_TUNNELING); UserInfo.h323_uu_pdu.bit_mask |= h245Tunneling_present; SetNonStandardData( UserInfo ); UserInfo.h323_uu_pdu.h323_message_body.choice = connect_chosen; connectMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; TransportAddress& transportAddress = connectMessage.h245Address; CopyTransportAddress( transportAddress, &m_selfH245Addr ); connectMessage.bit_mask |= (Connect_UUIE_h245Address_present); connectMessage.destinationInfo.bit_mask = 0; //copy the vendor info connectMessage.destinationInfo.bit_mask |= vendor_present; CopyVendorInfo( &connectMessage.destinationInfo.vendor ); //terminal is present connectMessage.destinationInfo.bit_mask |= terminal_present; connectMessage.destinationInfo.terminal.bit_mask = 0; connectMessage.destinationInfo.mc = 0; connectMessage.destinationInfo.undefinedNode = 0; //copy the 16 byte conference ID CopyConferenceID (&connectMessage.conferenceID, &m_ConferenceID); if( m_pFastStart != NULL ) { _ASSERTE( m_pPeerFastStart ); connectMessage.bit_mask |= Connect_UUIE_fastStart_present; connectMessage.fastStart = (PConnect_UUIE_fastStart)m_pFastStart; } else { connectMessage.bit_mask &= ~Alerting_UUIE_fastStart_present; } //copy the call identifier connectMessage.bit_mask |= Connect_UUIE_callIdentifier_present; CopyMemory( (PVOID)&connectMessage.callIdentifier.guid.value, (PVOID)&m_callIdentifier, sizeof(GUID) ); connectMessage.callIdentifier.guid.length = sizeof(GUID); rc = EncodeASN( (void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pdwEncodedLength); if (ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pdwEncodedLength == 0) ) { if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } return FALSE; } if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } H323DBG((DEBUG_LEVEL_TRACE, "EncodeConnectMessage exited: %p.", this )); //success return TRUE; } //!!always called in a lock void CH323Call::SetNonStandardData( OUT H323_UserInformation & UserInfo ) { if( m_NonStandardData.sData.pOctetString ) { H221NonStandard & nonStd = UserInfo.h323_uu_pdu.nonStandardData.nonStandardIdentifier.u.h221NonStandard; UserInfo.h323_uu_pdu.bit_mask |= H323_UU_PDU_nonStandardData_present; UserInfo.h323_uu_pdu.nonStandardData.nonStandardIdentifier.choice = H225NonStandardIdentifier_h221NonStandard_chosen; nonStd.t35CountryCode = m_NonStandardData.bCountryCode; nonStd.t35Extension = m_NonStandardData.bExtension; nonStd.manufacturerCode = m_NonStandardData.wManufacturerCode; UserInfo.h323_uu_pdu.nonStandardData.data.length = m_NonStandardData.sData.wOctetStringLength; UserInfo.h323_uu_pdu.nonStandardData.data.value = m_NonStandardData.sData.pOctetString; // Maintain only one reference to the buffer. m_NonStandardData.sData.pOctetString = NULL; } else { UserInfo.h323_uu_pdu.bit_mask &= (~H323_UU_PDU_nonStandardData_present); } } //!!always called in a lock BOOL CH323Call::EncodeSetupMessage( IN DWORD dwInvokeID, IN WORD wGoal, IN WORD wCallType, OUT BYTE **ppEncodedBuf, OUT WORD *pdwEncodedLength, IN DWORD dwAPDUType ) { H323_UU_PDU_h4501SupplementaryService h4501APDU; H323_UserInformation UserInfo; int rc = 0; BOOL retVal = TRUE; DWORD dwAPDULen = 0; BYTE* pEncodedAPDU = NULL; *ppEncodedBuf = NULL; *pdwEncodedLength = 0; H323DBG((DEBUG_LEVEL_TRACE, "EncodeSetupMessage entered: %p.", this )); Setup_UUIE & setupMessage = UserInfo.h323_uu_pdu.h323_message_body.u.setup; TransportAddress& calleeAddr = setupMessage.destCallSignalAddress; TransportAddress& callerAddr = setupMessage.sourceCallSignalAddress; memset( (PVOID)&UserInfo, 0, sizeof(H323_UserInformation)); UserInfo.bit_mask = 0; // make sure the user_data_present flag is turned off. UserInfo.bit_mask &= (~user_data_present); UserInfo.h323_uu_pdu.bit_mask = 0; //send the appropriate ADPDUS if( dwAPDUType != NO_H450_APDU ) { if( !EncodeH450APDU( dwInvokeID, dwAPDUType, &pEncodedAPDU, &dwAPDULen ) ) { return FALSE; } UserInfo.h323_uu_pdu.h4501SupplementaryService = &h4501APDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> next = NULL; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.value = pEncodedAPDU; UserInfo.h323_uu_pdu.h4501SupplementaryService -> value.length = dwAPDULen; UserInfo.h323_uu_pdu.bit_mask |= h4501SupplementaryService_present; } UserInfo.h323_uu_pdu.h245Tunneling = FALSE;//(m_fh245Tunneling & LOCAL_H245_TUNNELING); UserInfo.h323_uu_pdu.bit_mask |= h245Tunneling_present; SetNonStandardData( UserInfo ); UserInfo.h323_uu_pdu.h323_message_body.choice = setup_chosen; setupMessage.bit_mask = 0; setupMessage.protocolIdentifier = OID_H225ProtocolIdentifierV2; if( m_pCallerAliasNames && m_pCallerAliasNames -> wCount ) { //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); setupMessage.sourceAddress = SetMsgAddressAlias(m_pCallerAliasNames); if( setupMessage.sourceAddress != NULL ) { setupMessage.bit_mask |= (sourceAddress_present); } else { setupMessage.bit_mask &= (~sourceAddress_present); } } else { setupMessage.bit_mask &= (~sourceAddress_present); } setupMessage.sourceInfo.bit_mask = 0; //pass the vendor info setupMessage.sourceInfo.bit_mask |= vendor_present; CopyVendorInfo( &setupMessage.sourceInfo.vendor ); //terminal is present setupMessage.sourceInfo.bit_mask |= terminal_present; setupMessage.sourceInfo.terminal.bit_mask = 0; //not an MC setupMessage.sourceInfo.mc = FALSE; setupMessage.sourceInfo.undefinedNode = 0; if( m_pCalleeAliasNames && m_pCalleeAliasNames -> wCount ) { setupMessage.destinationAddress = (PSetup_UUIE_destinationAddress) SetMsgAddressAlias( m_pCalleeAliasNames ); if( setupMessage.destinationAddress != NULL ) { setupMessage.bit_mask |= (destinationAddress_present); } else { setupMessage.bit_mask &= (~destinationAddress_present); } } else { setupMessage.bit_mask &= (~destinationAddress_present); } //extra alias not present setupMessage.bit_mask &= (~Setup_UUIE_destExtraCallInfo_present ); //If talking to gateway then don't pass on destn call signal address if( m_dwAddressType != LINEADDRESSTYPE_PHONENUMBER ) { CopyTransportAddress( calleeAddr, &m_CalleeAddr ); setupMessage.bit_mask |= Setup_UUIE_destCallSignalAddress_present; } //not an MC setupMessage.activeMC = m_fActiveMC; //copy the 16 byte conference ID CopyConferenceID (&setupMessage.conferenceID, &m_ConferenceID); //copy the call identifier setupMessage.bit_mask |= Setup_UUIE_callIdentifier_present; CopyConferenceID (&setupMessage.callIdentifier.guid, &m_callIdentifier); //fast start params if( m_pFastStart != NULL ) { setupMessage.bit_mask |= Setup_UUIE_fastStart_present; setupMessage.fastStart = (PSetup_UUIE_fastStart)m_pFastStart; } else { setupMessage.bit_mask &= ~Setup_UUIE_fastStart_present; } //copy media wait for connect setupMessage.mediaWaitForConnect = FALSE; setupMessage.conferenceGoal.choice = (BYTE)wGoal; setupMessage.callType.choice = (BYTE)wCallType; CopyTransportAddress( callerAddr, &m_CallerAddr ); setupMessage.bit_mask |= sourceCallSignalAddress_present; //no extension alias setupMessage.bit_mask &= (~Setup_UUIE_remoteExtensionAddress_present); rc = EncodeASN( (void *) &UserInfo, H323_UserInformation_PDU, ppEncodedBuf, pdwEncodedLength); if( ASN1_FAILED(rc) || (*ppEncodedBuf == NULL) || (pdwEncodedLength == 0) ) { if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } retVal = FALSE; } // Free the alias name structures from the UserInfo area. if( setupMessage.bit_mask & sourceAddress_present ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) setupMessage.sourceAddress ); } if( setupMessage.bit_mask & destinationAddress_present ) { FreeAddressAliases( setupMessage.destinationAddress ); } if( pEncodedAPDU != NULL ) { ASN1_FreeEncoded(m_H450ASNCoderInfo.pEncInfo, pEncodedAPDU ); } H323DBG((DEBUG_LEVEL_TRACE, "EncodeSetupMessage exited: %p.", this )); //success/failure return retVal; } //!!always called in a lock BOOL CH323Call::EncodeH450APDU( IN DWORD dwInvokeID, IN DWORD dwAPDUType, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { H4501SupplementaryService SupplementaryServiceAPDU; ServiceApdus_rosApdus rosAPDU; DWORD dwErrorCode = 0; DWORD dwOperationType = (dwAPDUType & 0x0000FF00); dwAPDUType &= 0x000000FF; H323DBG((DEBUG_LEVEL_TRACE, "EncodeH450APDU entered: %p.", this )); ZeroMemory( (PVOID)&SupplementaryServiceAPDU, sizeof(H4501SupplementaryService) ); //interpretationAPDU SupplementaryServiceAPDU.interpretationApdu.choice = rejectAnyUnrecognizedInvokePdu_chosen; SupplementaryServiceAPDU.bit_mask |= interpretationApdu_present; //NFE SupplementaryServiceAPDU.networkFacilityExtension.bit_mask = 0; SupplementaryServiceAPDU.networkFacilityExtension.destinationEntity.choice = endpoint_chosen; SupplementaryServiceAPDU.networkFacilityExtension.sourceEntity.choice = endpoint_chosen; SupplementaryServiceAPDU.bit_mask |= networkFacilityExtension_present; //serviceAPDUS SupplementaryServiceAPDU.serviceApdu.choice = rosApdus_chosen; SupplementaryServiceAPDU.serviceApdu.u.rosApdus = &rosAPDU; SupplementaryServiceAPDU.serviceApdu.u.rosApdus->next = NULL; if( dwOperationType == H450_REJECT ) { if( !EncodeRejectAPDU( &SupplementaryServiceAPDU, dwInvokeID, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } } else if( dwOperationType == H450_RETURNERROR ) { EncodeReturnErrorAPDU( dwInvokeID, dwErrorCode, &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ); } else if( dwOperationType == H450_RETURNRESULT ) { if( !EncodeDummyReturnResultAPDU( dwInvokeID, dwAPDUType, &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } } else //H450_INVOKE { switch( dwAPDUType ) { case CHECKRESTRICTION_OPCODE: if( !EncodeCheckRestrictionAPDU( &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; case CALLREROUTING_OPCODE: if( !EncodeCallReroutingAPDU( &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; case DIVERTINGLEGINFO2_OPCODE: if( !EncodeDivertingLeg2APDU( &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; case DIVERTINGLEGINFO3_OPCODE: if( !EncodeDivertingLeg3APDU( &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; case HOLDNOTIFIC_OPCODE: case REMOTEHOLD_OPCODE: case RETRIEVENOTIFIC_OPCODE: case REMOTERETRIEVE_OPCODE: case CTIDENTIFY_OPCODE: if( !EncodeH450APDUNoArgument( dwAPDUType, &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; case CTSETUP_OPCODE: if( !EncodeCTSetupAPDU( &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; case CTINITIATE_OPCODE: if( !EncodeCTInitiateAPDU( &SupplementaryServiceAPDU, ppEncodedAPDU, pdwAPDULen ) ) { return FALSE; } break; default: _ASSERTE( 0 ); return FALSE; } } H323DBG((DEBUG_LEVEL_TRACE, "EncodeH450APDU exited: %p.", this )); return TRUE; } //!!always called in a lock BOOL CH323Call::EncodePDU( IN BINARY_STRING *pUserUserData, OUT BYTE ** ppbCodedBuffer, OUT DWORD * pdwCodedBufferLength, IN DWORD dwMessageType, WCHAR * pwszCalledPartyNumber ) { PQ931MESSAGE pMessage; BYTE bBandwidth; char pszDisplay[131] = ""; DWORD dwMessageLength = 0; BYTE indexI; BOOL retVal; H323DBG(( DEBUG_LEVEL_TRACE, "EncodePDU entered: %p.", this )); pMessage = new Q931MESSAGE; if( pMessage == NULL ) { return FALSE; } // fill in the required fields for the Q931 message. memset( (PVOID)pMessage, 0, sizeof(Q931MESSAGE)); pMessage->ProtocolDiscriminator = Q931PDVALUE; pMessage->wCallRef = m_wQ931CallRef; pMessage->MessageType = (BYTE)dwMessageType; dwMessageLength += ( 1 + sizeof(PDTYPE) + sizeof(CRTYPE) + sizeof(MESSAGEIDTYPE) ); if( (dwMessageType == SETUPMESSAGETYPE) || (dwMessageType == CONNECTMESSAGETYPE) ) { if( m_pwszDisplay && WideCharToMultiByte(CP_ACP, 0, m_pwszDisplay, -1, pszDisplay, sizeof(pszDisplay), NULL, NULL) == 0) { delete pMessage; return FALSE; } if( *pszDisplay ) { pMessage->Display.fPresent = TRUE; pMessage->Display.dwLength = (BYTE)(strlen(pszDisplay) + 1); strcpy((char *)pMessage->Display.pbContents, pszDisplay); dwMessageLength += (2 + pMessage->Display.dwLength); } pMessage->BearerCapability.fPresent = TRUE; pMessage->BearerCapability.dwLength = 3; pMessage->BearerCapability.pbContents[0] = (BYTE)(BEAR_EXT_BIT | BEAR_CCITT | BEAR_UNRESTRICTED_DIGITAL); pMessage->BearerCapability.pbContents[1] = (BYTE)(BEAR_EXT_BIT | 0x17); //64kbps pMessage->BearerCapability.pbContents[2] = (BYTE) (BEAR_EXT_BIT | BEAR_LAYER1_INDICATOR | BEAR_LAYER1_H221_H242); dwMessageLength += (2+pMessage->BearerCapability.dwLength); } //if talking to gateway encode the called party number if( m_dwAddressType == LINEADDRESSTYPE_PHONENUMBER ) { BYTE bLen = (BYTE)(wcslen(pwszCalledPartyNumber)+1); pMessage->CalledPartyNumber.fPresent = TRUE; pMessage->CalledPartyNumber.NumberType = (BYTE)(CALLED_PARTY_EXT_BIT | CALLED_PARTY_TYPE_UNKNOWN); pMessage->CalledPartyNumber.NumberingPlan = (BYTE)(CALLED_PARTY_PLAN_E164); pMessage->CalledPartyNumber.PartyNumberLength = bLen; for( indexI =0; indexI < bLen; indexI++ ) { pMessage->CalledPartyNumber.PartyNumbers[indexI] = (BYTE)pwszCalledPartyNumber[indexI]; } dwMessageLength += (2 + pMessage->CalledPartyNumber.PartyNumberLength); } if( dwMessageType == FACILITYMESSAGETYPE ) { // The facility ie is encoded as present, but empty... pMessage->Facility.fPresent = TRUE; pMessage->Facility.dwLength = 0; pMessage->Facility.pbContents[0] = 0; dwMessageLength += (2 + pMessage->Facility.dwLength); } if (pUserUserData && pUserUserData->pbBuffer) { if (pUserUserData->length > sizeof(pMessage->UserToUser.pbUserInfo)) { delete pMessage; return FALSE; } pMessage->UserToUser.fPresent = TRUE; pMessage->UserToUser.wUserInfoLen = pUserUserData->length; //This CopyMemory should be avoided //may be we should do:pMessage->UserToUser.pbUserInfo = pUserUserData->pbBuffer; //change the definition of pMessage->UserToUser.pbUserInfo to BYTE* from BYTE[0x1000] CopyMemory( (PVOID)pMessage->UserToUser.pbUserInfo, (PVOID)pUserUserData->pbBuffer, pUserUserData->length ); dwMessageLength += (4+pMessage->UserToUser.wUserInfoLen); } _ASSERTE( dwMessageLength ); retVal = EncodeMessage( pMessage, ppbCodedBuffer, pdwCodedBufferLength, dwMessageLength ); delete pMessage; return retVal; } //!!always called in a lock BOOL CH323Call::EncodeMessage( IN PQ931MESSAGE pMessage, OUT BYTE **ppbCodedMessage, OUT DWORD *pdwCodedMessageLength, IN DWORD dwMessageLength ) { BUFFERDESCR pBuf; DWORD dwPDULen = 0; H323DBG((DEBUG_LEVEL_TRACE, "EncodeMessage entered: %p.", this )); *ppbCodedMessage = (BYTE *)new char[ dwMessageLength + 100 ]; if( *ppbCodedMessage == NULL ) { return FALSE; } pBuf.dwLength = dwMessageLength + 100; pBuf.pbBuffer = *ppbCodedMessage + TPKT_HEADER_SIZE; WriteQ931Fields(&pBuf, pMessage, &dwPDULen ); _ASSERTE( dwPDULen == dwMessageLength ); SetupTPKTHeader( *ppbCodedMessage , dwPDULen ); *pdwCodedMessageLength = dwPDULen + 4; H323DBG((DEBUG_LEVEL_TRACE, "EncodeMessage exited: %p.", this )); return TRUE; } //!!always called in a lock void CH323Call::WriteQ931Fields( IN PBUFFERDESCR pBuf, IN PQ931MESSAGE pMessage, OUT DWORD * pdwPDULen ) { H323DBG((DEBUG_LEVEL_TRACE, "WriteQ931Fields entered: %p.", this )); // write the required information elements... WriteProtocolDiscriminator( pBuf, pdwPDULen ); WriteCallReference( pBuf, &pMessage->wCallRef, pdwPDULen ); WriteMessageType(pBuf, &pMessage->MessageType, pdwPDULen); // try to write all other information elements... // don't write this message. if (pMessage->Facility.fPresent) { WriteVariableOctet(pBuf, IDENT_FACILITY, pMessage->Facility.dwLength, pMessage->Facility.pbContents, pdwPDULen); } if( pMessage->BearerCapability.fPresent && pMessage->BearerCapability.dwLength ) { WriteVariableOctet(pBuf, IDENT_BEARERCAP, pMessage->BearerCapability.dwLength, pMessage->BearerCapability.pbContents, pdwPDULen); } if (pMessage->Display.fPresent && pMessage->Display.dwLength) { WriteVariableOctet(pBuf, IDENT_DISPLAY, pMessage->Display.dwLength, pMessage->Display.pbContents, pdwPDULen); } if( pMessage->CalledPartyNumber.fPresent ) { WritePartyNumber(pBuf, IDENT_CALLEDNUMBER, pMessage->CalledPartyNumber.NumberType, pMessage->CalledPartyNumber.NumberingPlan, pMessage->CalledPartyNumber.PartyNumberLength, pMessage->CalledPartyNumber.PartyNumbers, pdwPDULen); } if( pMessage->UserToUser.fPresent && pMessage->UserToUser.wUserInfoLen ) { WriteUserInformation(pBuf, IDENT_USERUSER, pMessage->UserToUser.wUserInfoLen, pMessage->UserToUser.pbUserInfo, pdwPDULen); } H323DBG((DEBUG_LEVEL_TRACE, "WriteQ931Fields exited: %p.", this )); } //!!always calld in a lock void CH323Call::HandleTransportEvent(void) { WSANETWORKEVENTS networkEvents; int iError; H323DBG(( DEBUG_LEVEL_TRACE, "HandleTransportEvent entered: %p.", this )); if( (m_callSocket == INVALID_SOCKET) && (m_dwCallType == CALLTYPE_DIVERTEDSRC) ) { H323DBG(( DEBUG_LEVEL_TRACE, "The diverted call is not initialized yet." "This is probably an event for the primary call. Ignore it %p.", this )); return; } //find out the event that took place if(WSAEnumNetworkEvents(m_callSocket, m_hTransport, &networkEvents ) == SOCKET_ERROR ) { H323DBG((DEBUG_LEVEL_TRACE, "WSAEnumNetworkEvents error:%d, %lx, %p.", WSAGetLastError(), m_callSocket, this )); return; } if( networkEvents.lNetworkEvents & FD_CLOSE ) { H323DBG((DEBUG_LEVEL_TRACE, "socket close event: %p.", this )); //if the call is in transition then don't close the call when the //old socket gets closed if( m_fCallInTrnasition == TRUE ) { //the call is noot in transition mode anymore m_fCallInTrnasition = FALSE; return; } //convey the Q931 close status to the TAPI call object //and the tapisrv iError = networkEvents.iErrorCode[FD_CLOSE_BIT]; SetQ931CallState( Q931_CALL_DISCONNECTED ); //clean up the Q931 call CloseCall( 0 ); return; } //This can occur only for outbound calls if( (networkEvents.lNetworkEvents) & FD_CONNECT ) { H323DBG((DEBUG_LEVEL_TRACE, "socket connect event: %p.", this )); //FD_CONNECT event received //This func is called by the callback thread when m_hEventQ931Conn is //signalled. This function takes care of the outgoing Q931 calls only //call the member function iError = networkEvents.iErrorCode[FD_CONNECT_BIT]; if(iError != ERROR_SUCCESS) { if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&& (m_dwOrigin == LINECALLORIGIN_OUTBOUND ) ) { //Success of forwarding EnableCallForwarding(); } H323DBG((DEBUG_LEVEL_ERROR, "FD_CONNECT returned error: %d.", iError )); CloseCall( 0 ); return; } OnConnectComplete(); } H323DBG((DEBUG_LEVEL_TRACE, "HandleTransportEvent exited: %p.", this )); } //!!always called in a lock int CH323Call::InitASNCoder(void) { int rc; H323DBG((DEBUG_LEVEL_TRACE, "InitASNCoder entered: %p.", this )); memset((PVOID)&m_ASNCoderInfo, 0, sizeof(m_ASNCoderInfo)); if( H225ASN_Module == NULL) { return ASN1_ERR_BADARGS; } rc = ASN1_CreateEncoder( H225ASN_Module, // ptr to mdule &(m_ASNCoderInfo.pEncInfo), // ptr to encoder info NULL, // buffer ptr 0, // buffer size NULL); // parent ptr if (rc == ASN1_SUCCESS) { _ASSERTE(m_ASNCoderInfo.pEncInfo ); rc = ASN1_CreateDecoder( H225ASN_Module, // ptr to mdule &(m_ASNCoderInfo.pDecInfo), // ptr to decoder info NULL, // buffer ptr 0, // buffer size NULL); // parent ptr _ASSERTE(m_ASNCoderInfo.pDecInfo ); } if (rc != ASN1_SUCCESS) { TermASNCoder(); } H323DBG((DEBUG_LEVEL_TRACE, "InitASNCoder exited: %p.", this )); return rc; } //!!always called in a lock int CH323Call::TermASNCoder(void) { if( H225ASN_Module == NULL ) { return ASN1_ERR_BADARGS; } ASN1_CloseEncoder(m_ASNCoderInfo.pEncInfo); ASN1_CloseDecoder(m_ASNCoderInfo.pDecInfo); memset( (PVOID)&m_ASNCoderInfo, 0, sizeof(m_ASNCoderInfo)); return ASN1_SUCCESS; } //!!always called in a lock int CH323Call::EncodeASN( IN void * pStruct, IN int nPDU, OUT BYTE ** ppEncoded, OUT WORD * pcbEncodedSize ) { H323DBG((DEBUG_LEVEL_TRACE, "EncodeASN entered: %p.", this )); ASN1encoding_t pEncInfo = m_ASNCoderInfo.pEncInfo; int rc = ASN1_Encode( pEncInfo, // ptr to encoder info pStruct, // pdu data structure nPDU, // pdu id ASN1ENCODE_ALLOCATEBUFFER, // flags NULL, // do not provide buffer 0); // buffer size if provided if (ASN1_SUCCEEDED(rc)) { if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_TRACE, "warning while encoding ASN:%d.", rc )); } *pcbEncodedSize = (WORD)pEncInfo->len; // len of encoded data in buffer *ppEncoded = pEncInfo->buf; // buffer to encode into } else { H323DBG((DEBUG_LEVEL_TRACE, "error while encoding ASN:%d.", rc )); *pcbEncodedSize = 0; *ppEncoded = NULL; } H323DBG((DEBUG_LEVEL_TRACE, "EncodeASN exited: %p.", this )); return rc; } //!!always called in a lock int CH323Call::DecodeASN( OUT void ** ppStruct, IN int nPDU, IN BYTE * pEncoded, IN DWORD cbEncodedSize ) { H323DBG((DEBUG_LEVEL_TRACE, "h323call DecodeASN entered: %p.", this )); ASN1decoding_t pDecInfo = m_ASNCoderInfo.pDecInfo; int rc = ASN1_Decode( pDecInfo, // ptr to encoder info ppStruct, // pdu data structure nPDU, // pdu id ASN1DECODE_SETBUFFER, // flags pEncoded, // do not provide buffer cbEncodedSize); // buffer size if provided if (ASN1_SUCCEEDED(rc)) { if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_TRACE, "warning while deciding ASN:%d.", rc )); } } else { H323DBG((DEBUG_LEVEL_TRACE, "error while deciding ASN:%d.", rc )); H323DUMPBUFFER( (BYTE*)pEncoded, cbEncodedSize); *ppStruct = NULL; } H323DBG((DEBUG_LEVEL_TRACE, "h323call DecodeASN exited: %p.", this )); return rc; } //!!always called in a lock int CH323Call::InitH450ASNCoder(void) { int rc; H323DBG((DEBUG_LEVEL_TRACE, "InitH450ASNCoder entered: %p.", this )); memset((PVOID)&m_H450ASNCoderInfo, 0, sizeof(m_H450ASNCoderInfo)); if( H4503PP_Module == NULL) { return ASN1_ERR_BADARGS; } rc = ASN1_CreateEncoder( H4503PP_Module, // ptr to mdule &(m_H450ASNCoderInfo.pEncInfo), // ptr to encoder info NULL, // buffer ptr 0, // buffer size NULL); // parent ptr if (rc == ASN1_SUCCESS) { _ASSERTE(m_H450ASNCoderInfo.pEncInfo ); rc = ASN1_CreateDecoder( H4503PP_Module, // ptr to mdule &(m_H450ASNCoderInfo.pDecInfo), // ptr to decoder info NULL, // buffer ptr 0, // buffer size NULL ); // parent ptr _ASSERTE( m_H450ASNCoderInfo.pDecInfo ); } if (rc != ASN1_SUCCESS) { TermH450ASNCoder(); } H323DBG((DEBUG_LEVEL_TRACE, "InitH450ASNCoder exited: %p.", this )); return rc; } //!!always called in a lock int CH323Call::TermH450ASNCoder(void) { if( H4503PP_Module == NULL ) { return ASN1_ERR_BADARGS; } ASN1_CloseEncoder(m_H450ASNCoderInfo.pEncInfo); ASN1_CloseDecoder(m_H450ASNCoderInfo.pDecInfo); memset( (PVOID)&m_H450ASNCoderInfo, 0, sizeof(m_ASNCoderInfo)); return ASN1_SUCCESS; } //!!always called in a lock int CH323Call::EncodeH450ASN( IN void * pStruct, IN int nPDU, OUT BYTE ** ppEncoded, OUT WORD * pcbEncodedSize ) { H323DBG((DEBUG_LEVEL_TRACE, "EncodeH450ASN entered: %p.", this )); ASN1encoding_t pEncInfo = m_H450ASNCoderInfo.pEncInfo; int rc = ASN1_Encode( pEncInfo, // ptr to encoder info pStruct, // pdu data structure nPDU, // pdu id ASN1ENCODE_ALLOCATEBUFFER, // flags NULL, // do not provide buffer 0); // buffer size if provided if (ASN1_SUCCEEDED(rc)) { if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_TRACE, "warning while encoding ASN:%d.", rc )); } *pcbEncodedSize = (WORD)pEncInfo->len; // len of encoded data in buffer *ppEncoded = pEncInfo->buf; // buffer to encode into } else { H323DBG((DEBUG_LEVEL_TRACE, "error while encoding ASN:%d.", rc )); *pcbEncodedSize = 0; *ppEncoded = NULL; } H323DBG((DEBUG_LEVEL_TRACE, "EncodeH450ASN exited: %p.", this )); return rc; } //!!always called in a lock int CH323Call::DecodeH450ASN( OUT void ** ppStruct, IN int nPDU, IN BYTE * pEncoded, IN DWORD cbEncodedSize ) { H323DBG((DEBUG_LEVEL_TRACE, "h323call DecodeH450ASN entered: %p.", this )); ASN1decoding_t pDecInfo = m_H450ASNCoderInfo.pDecInfo; int rc = ASN1_Decode( pDecInfo, // ptr to encoder info ppStruct, // pdu data structure nPDU, // pdu id ASN1DECODE_SETBUFFER, // flags pEncoded, // do not provide buffer cbEncodedSize); // buffer size if provided if( ASN1_SUCCEEDED(rc) ) { if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_TRACE, "warning while deciding ASN:%d.", rc )); } } else { H323DBG((DEBUG_LEVEL_TRACE, "error while deciding ASN:%d.", rc )); H323DUMPBUFFER( (BYTE*)pEncoded, cbEncodedSize); *ppStruct = NULL; } H323DBG(( DEBUG_LEVEL_TRACE, "h323call DecodeH450ASN exited: %p.", this )); return rc; } //------------------------------------------------------------------------ //------------------------------------------------------------------------ //!!always called in a lock BOOL CH323Call::ParseReleaseCompleteASN( IN BYTE *pEncodedBuf, IN DWORD dwEncodedLength, OUT Q931_RELEASE_COMPLETE_ASN *pReleaseASN, OUT DWORD* pdwH450APDUType ) { H323_UserInformation *pUserInfo; int iResult; DWORD dwInvokeID = 0; H323DBG((DEBUG_LEVEL_TRACE, "ParseReleaseCompleteASN entered: %p.", this )); memset( (PVOID)pReleaseASN, 0, sizeof(Q931_RELEASE_COMPLETE_ASN)); iResult = DecodeASN((void **) &pUserInfo, H323_UserInformation_PDU, pEncodedBuf, dwEncodedLength); if (ASN1_FAILED(iResult) || (pUserInfo == NULL)) { return FALSE; } *pdwH450APDUType = 0; if( (pUserInfo->h323_uu_pdu.bit_mask & h4501SupplementaryService_present) && pUserInfo->h323_uu_pdu.h4501SupplementaryService ) { if( !HandleH450APDU( pUserInfo->h323_uu_pdu.h4501SupplementaryService, pdwH450APDUType, &dwInvokeID, NULL ) ) { goto cleanup; } } // validate that the PDU user-data uses ASN encoding. if( (pUserInfo->bit_mask & user_data_present) && (pUserInfo->user_data.protocol_discriminator != USE_ASN1_ENCODING) ) { goto cleanup; } // validate that the PDU is H323 Release Complete information. if( pUserInfo->h323_uu_pdu.h323_message_body.choice != releaseComplete_chosen ) { goto cleanup; } // parse the message contained in pUserInfo. pReleaseASN->fNonStandardDataPresent = FALSE; if( pUserInfo->h323_uu_pdu.bit_mask & H323_UU_PDU_nonStandardData_present ) { if( !ParseNonStandardData( &pReleaseASN -> nonStandardData, &pUserInfo->h323_uu_pdu.nonStandardData ) ) { goto cleanup; } pReleaseASN->fNonStandardDataPresent = TRUE; } if (pUserInfo->h323_uu_pdu.h323_message_body.u.releaseComplete.bit_mask & ReleaseComplete_UUIE_reason_present) { switch( pUserInfo->h323_uu_pdu.h323_message_body.u.releaseComplete.reason.choice ) { case noBandwidth_chosen: pReleaseASN->bReason = H323_REJECT_NO_BANDWIDTH; break; case gatekeeperResources_chosen: pReleaseASN->bReason = H323_REJECT_GATEKEEPER_RESOURCES; break; case unreachableDestination_chosen: pReleaseASN->bReason = H323_REJECT_UNREACHABLE_DESTINATION; break; case destinationRejection_chosen: pReleaseASN->bReason = H323_REJECT_DESTINATION_REJECTION; break; case ReleaseCompleteReason_invalidRevision_chosen: pReleaseASN->bReason = H323_REJECT_INVALID_REVISION; break; case noPermission_chosen: pReleaseASN->bReason = H323_REJECT_NO_PERMISSION; break; case unreachableGatekeeper_chosen: pReleaseASN->bReason = H323_REJECT_UNREACHABLE_GATEKEEPER; break; case gatewayResources_chosen: pReleaseASN->bReason = H323_REJECT_GATEWAY_RESOURCES; break; case badFormatAddress_chosen: pReleaseASN->bReason = H323_REJECT_BAD_FORMAT_ADDRESS; break; case adaptiveBusy_chosen: pReleaseASN->bReason = H323_REJECT_ADAPTIVE_BUSY; break; case inConf_chosen: pReleaseASN->bReason = H323_REJECT_IN_CONF; break; case facilityCallDeflection_chosen: pReleaseASN->bReason = H323_REJECT_CALL_DEFLECTION; break; default: pReleaseASN->bReason = H323_REJECT_UNDEFINED_REASON; } // switch } else { pReleaseASN->bReason = H323_REJECT_UNDEFINED_REASON; } H323DBG(( DEBUG_LEVEL_TRACE, "ParseReleaseCompleteASN error:%d, q931 error:%d, exit:%p.", pReleaseASN->bReason, pUserInfo->h323_uu_pdu.h323_message_body.u.releaseComplete.reason.choice, this )); // Free the PDU data. ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); return TRUE; cleanup: if( pReleaseASN->fNonStandardDataPresent ) { delete pReleaseASN -> nonStandardData.sData.pOctetString; pReleaseASN -> nonStandardData.sData.pOctetString = NULL; pReleaseASN->fNonStandardDataPresent = FALSE; } ASN1_FreeDecoded( m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU); return FALSE; } //------------------------------------------------------------------------ //------------------------------------------------------------------------ //!!always called in a lock BOOL CH323Call::ParseConnectASN( IN BYTE *pEncodedBuf, IN DWORD dwEncodedLength, OUT Q931_CONNECT_ASN *pConnectASN, OUT DWORD* pdwH450APDUType ) { H323_UserInformation *pUserInfo; int iResult; DWORD dwInvokeID = 0; H323DBG((DEBUG_LEVEL_TRACE, "ParseConnectASN entered: %p.", this )); memset( (PVOID) pConnectASN, 0, sizeof(Q931_CONNECT_ASN) ); iResult = DecodeASN((void **) &pUserInfo , H323_UserInformation_PDU, pEncodedBuf, dwEncodedLength); if (ASN1_FAILED(iResult) || (pUserInfo == NULL)) { return FALSE; } Connect_UUIE & connectMessage = pUserInfo->h323_uu_pdu.h323_message_body.u.connect; *pdwH450APDUType = 0; if( (pUserInfo->h323_uu_pdu.bit_mask & h4501SupplementaryService_present) && pUserInfo->h323_uu_pdu.h4501SupplementaryService ) { if( !HandleH450APDU( pUserInfo->h323_uu_pdu.h4501SupplementaryService, pdwH450APDUType, &dwInvokeID, NULL ) ) { goto cleanup; } } // validate that the PDU user-data uses ASN encoding. if( (pUserInfo->bit_mask & user_data_present) && (pUserInfo->user_data.protocol_discriminator != USE_ASN1_ENCODING) ) { goto cleanup; } // validate that the PDU is H323 Connect information. if (pUserInfo->h323_uu_pdu.h323_message_body.choice != connect_chosen) { goto cleanup; } // make sure that the conference id is formed correctly. if (connectMessage.conferenceID.length > sizeof(connectMessage.conferenceID.value)) { goto cleanup; } // parse the message contained in pUserInfo. pConnectASN->h245Addr.bMulticast = FALSE; pConnectASN->fNonStandardDataPresent = FALSE; if( pUserInfo->h323_uu_pdu.bit_mask & H323_UU_PDU_nonStandardData_present ) { if( !ParseNonStandardData( &pConnectASN -> nonStandardData, &pUserInfo->h323_uu_pdu.nonStandardData ) ) { goto cleanup; } pConnectASN->fNonStandardDataPresent = TRUE; } pConnectASN->h245AddrPresent = FALSE; if( connectMessage.bit_mask & Connect_UUIE_h245Address_present ) { if( connectMessage.h245Address.choice != ipAddress_chosen ) { goto cleanup; } pConnectASN->h245Addr.nAddrType = H323_IP_BINARY; pConnectASN->h245Addr.Addr.IP_Binary.wPort = connectMessage.h245Address.u.ipAddress.port; pConnectASN->h245Addr.Addr.IP_Binary.dwAddr = ntohl( *((DWORD*)connectMessage.h245Address.u.ipAddress.ip.value) ); pConnectASN->h245AddrPresent = TRUE; } // no validation of destinationInfo needed. pConnectASN->EndpointType.pVendorInfo = NULL; if( connectMessage.destinationInfo.bit_mask & (vendor_present)) { if( !ParseVendorInfo( &pConnectASN->VendorInfo, &connectMessage.destinationInfo.vendor) ) { goto cleanup; } pConnectASN->EndpointType.pVendorInfo = &(pConnectASN->VendorInfo); } pConnectASN->EndpointType.bIsTerminal = FALSE; if (connectMessage.destinationInfo.bit_mask & (terminal_present)) { pConnectASN->EndpointType.bIsTerminal = TRUE; } pConnectASN->EndpointType.bIsGateway = FALSE; if (connectMessage.destinationInfo.bit_mask & (gateway_present)) { pConnectASN->EndpointType.bIsGateway = TRUE; } pConnectASN -> fFastStartPresent = FALSE; if( (connectMessage.bit_mask & Connect_UUIE_fastStart_present) && connectMessage.fastStart ) { pConnectASN->pFastStart = CopyFastStart( (PSetup_UUIE_fastStart)connectMessage.fastStart ); if( pConnectASN->pFastStart != NULL ) { pConnectASN -> fFastStartPresent = TRUE; } } CopyConferenceID( &pConnectASN -> ConferenceID, &connectMessage.conferenceID ); if( pUserInfo->h323_uu_pdu.h245Tunneling ) { //the remote endpoint has sent a tunneling proposal m_fh245Tunneling |= REMOTE_H245_TUNNELING; } // Free the PDU data. ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU); H323DBG((DEBUG_LEVEL_TRACE, "ParseConnectASN exited: %p.", this )); return TRUE; cleanup: FreeConnectASN( pConnectASN ); ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); return FALSE; } //!!always called in a lock BOOL CH323Call::ParseAlertingASN( IN BYTE *pEncodedBuf, IN DWORD dwEncodedLength, OUT Q931_ALERTING_ASN *pAlertingASN, OUT DWORD* pdwH450APDUType ) { H323_UserInformation *pUserInfo; int iResult; DWORD dwInvokeID = 0; H323DBG((DEBUG_LEVEL_TRACE, "ParseAlertingASN entered: %p.", this )); memset( (PVOID) pAlertingASN, 0, sizeof(Q931_ALERTING_ASN) ); iResult = DecodeASN((void **) &pUserInfo, H323_UserInformation_PDU, pEncodedBuf, dwEncodedLength); if (ASN1_FAILED(iResult) || (pUserInfo == NULL)) { return FALSE; } Alerting_UUIE & alertingMessage = pUserInfo->h323_uu_pdu.h323_message_body.u.alerting; *pdwH450APDUType = 0; if( (pUserInfo->h323_uu_pdu.bit_mask & h4501SupplementaryService_present) && pUserInfo->h323_uu_pdu.h4501SupplementaryService ) { if( !HandleH450APDU( pUserInfo->h323_uu_pdu.h4501SupplementaryService, pdwH450APDUType, &dwInvokeID, NULL ) ) { goto cleanup; } } // validate that the PDU user-data uses ASN encoding. if( (pUserInfo->bit_mask & user_data_present ) && (pUserInfo->user_data.protocol_discriminator != USE_ASN1_ENCODING) ) { goto cleanup; } // validate that the PDU is H323 Alerting information. if (pUserInfo->h323_uu_pdu.h323_message_body.choice != alerting_chosen) { goto cleanup; } // parse the message contained in pUserInfo. pAlertingASN->h245Addr.bMulticast = FALSE; pAlertingASN->fNonStandardDataPresent = FALSE; if( pUserInfo->h323_uu_pdu.bit_mask & H323_UU_PDU_nonStandardData_present ) { if( !ParseNonStandardData( &pAlertingASN -> nonStandardData, &pUserInfo->h323_uu_pdu.nonStandardData ) ) { goto cleanup; } pAlertingASN->fNonStandardDataPresent = TRUE; } if( alertingMessage.bit_mask & Alerting_UUIE_h245Address_present ) { if( alertingMessage.h245Address.choice != ipAddress_chosen ) { goto cleanup; } pAlertingASN->h245Addr.nAddrType = H323_IP_BINARY; pAlertingASN->h245Addr.Addr.IP_Binary.wPort = alertingMessage.h245Address.u.ipAddress.port; AddressReverseAndCopy( &(pAlertingASN->h245Addr.Addr.IP_Binary.dwAddr), alertingMessage.h245Address.u.ipAddress.ip.value ); } pAlertingASN -> fFastStartPresent = FALSE; if( (alertingMessage.bit_mask & Alerting_UUIE_fastStart_present) && alertingMessage.fastStart ) { pAlertingASN->pFastStart = CopyFastStart( (PSetup_UUIE_fastStart)alertingMessage.fastStart); if( pAlertingASN->pFastStart != NULL ) pAlertingASN-> fFastStartPresent = TRUE; } if( pUserInfo->h323_uu_pdu.h245Tunneling ) { m_fh245Tunneling |= REMOTE_H245_TUNNELING; } // Free the PDU data. ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU); H323DBG((DEBUG_LEVEL_TRACE, "ParseAlertingASN exited: %p.", this )); return TRUE; cleanup: FreeAlertingASN( pAlertingASN ); ASN1_FreeDecoded( m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); return FALSE; } //!!aleways called in a lock BOOL CH323Call::ParseProceedingASN( IN BYTE *pEncodedBuf, IN DWORD dwEncodedLength, OUT Q931_CALL_PROCEEDING_ASN *pProceedingASN, OUT DWORD* pdwH450APDUType ) { H323_UserInformation * pUserInfo; int iResult; DWORD dwInvokeID = 0; H323DBG((DEBUG_LEVEL_TRACE, "ParseProceedingASN entered: %p.", this )); memset( (PVOID) pProceedingASN, 0, sizeof(Q931_CALL_PROCEEDING_ASN) ); iResult = DecodeASN((void **) &pUserInfo, H323_UserInformation_PDU, pEncodedBuf, dwEncodedLength); if (ASN1_FAILED(iResult) || (pUserInfo == NULL)) { return FALSE; } CallProceeding_UUIE & proceedingMessage = pUserInfo->h323_uu_pdu.h323_message_body.u.callProceeding; *pdwH450APDUType = 0; if( (pUserInfo->h323_uu_pdu.bit_mask & h4501SupplementaryService_present) && pUserInfo->h323_uu_pdu.h4501SupplementaryService ) { if( !HandleH450APDU( pUserInfo->h323_uu_pdu.h4501SupplementaryService, pdwH450APDUType, &dwInvokeID, NULL ) ) goto cleanup; } // validate that the PDU user-data uses ASN encoding. if( (pUserInfo->bit_mask & user_data_present) && (pUserInfo->user_data.protocol_discriminator != USE_ASN1_ENCODING) ) { goto cleanup; } // validate that the PDU is H323 Proceeding information. // validate that the PDU is H323 pCall Proceeding information. if( pUserInfo->h323_uu_pdu.h323_message_body.choice != callProceeding_chosen ) { goto cleanup; } // parse the message contained in pUserInfo. pProceedingASN->fNonStandardDataPresent = FALSE; if( pUserInfo->h323_uu_pdu.bit_mask & H323_UU_PDU_nonStandardData_present ) { if( !ParseNonStandardData( &pProceedingASN -> nonStandardData, &pUserInfo->h323_uu_pdu.nonStandardData ) ) { goto cleanup; } pProceedingASN->fNonStandardDataPresent = TRUE; } //copy the H245 address information pProceedingASN->fH245AddrPresent = FALSE; if( proceedingMessage.bit_mask & CallProceeding_UUIE_h245Address_present ) { if( proceedingMessage.h245Address.choice != ipAddress_chosen ) { goto cleanup; } pProceedingASN->h245Addr.nAddrType = H323_IP_BINARY; pProceedingASN->h245Addr.Addr.IP_Binary.wPort = proceedingMessage.h245Address.u.ipAddress.port; AddressReverseAndCopy( &(pProceedingASN->h245Addr.Addr.IP_Binary.dwAddr), proceedingMessage.h245Address.u.ipAddress.ip.value ); pProceedingASN->h245Addr.bMulticast = FALSE; pProceedingASN->fH245AddrPresent = TRUE; } pProceedingASN -> fFastStartPresent = FALSE; if( (proceedingMessage.bit_mask & CallProceeding_UUIE_fastStart_present) && proceedingMessage.fastStart ) { pProceedingASN->pFastStart = CopyFastStart( (PSetup_UUIE_fastStart)proceedingMessage.fastStart); if( pProceedingASN->pFastStart != NULL ) pProceedingASN-> fFastStartPresent = TRUE; } //ignore the destinationInfo field. if( pUserInfo->h323_uu_pdu.h245Tunneling ) { if( m_dwOrigin == LINECALLORIGIN_INBOUND ) { //the msp has enabled tunneling in ProceedWithAnswer messsage m_fh245Tunneling |= LOCAL_H245_TUNNELING; } else //the remote endpoint has sent a tunneling proposal m_fh245Tunneling |= REMOTE_H245_TUNNELING; } // Free the PDU data. ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); H323DBG((DEBUG_LEVEL_TRACE, "ParseProceedingASN exited: %p.", this )); return TRUE; cleanup: FreeProceedingASN( pProceedingASN ); ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); return FALSE; } //!!always called in a lock BOOL CH323Call::ParseFacilityASN( IN BYTE * pEncodedBuf, IN DWORD dwEncodedLength, OUT Q931_FACILITY_ASN * pFacilityASN ) { H323_UserInformation *pUserInfo; int iResult; H323DBG((DEBUG_LEVEL_TRACE, "ParseFacilityASN entered: %p.", this )); ZeroMemory( (PVOID) pFacilityASN, sizeof(Q931_FACILITY_ASN) ); iResult = DecodeASN((void **) &pUserInfo, H323_UserInformation_PDU, pEncodedBuf, dwEncodedLength); if( ASN1_FAILED(iResult) || (pUserInfo == NULL) ) { return FALSE; } // validate that the PDU is H323 facility information. if( pUserInfo->h323_uu_pdu.h323_message_body.choice == facility_chosen ) { Facility_UUIE & facilityMessage = pUserInfo->h323_uu_pdu.h323_message_body.u.facility; // validate that the PDU user-data uses ASN encoding. if( (pUserInfo->bit_mask & user_data_present) && (pUserInfo->user_data.protocol_discriminator != USE_ASN1_ENCODING) ) { goto cleanup; } // make sure that the conference id is formed correctly. if( facilityMessage.conferenceID.length > sizeof(facilityMessage.conferenceID.value) ) { //goto cleanup; } // parse the message contained in pUserInfo. pFacilityASN->fNonStandardDataPresent = FALSE; if( pUserInfo->h323_uu_pdu.bit_mask & H323_UU_PDU_nonStandardData_present ) { if( !ParseNonStandardData( &pFacilityASN -> nonStandardData, &pUserInfo->h323_uu_pdu.nonStandardData ) ) { goto cleanup; } pFacilityASN->fNonStandardDataPresent = TRUE; } pFacilityASN->fAlternativeAddressPresent = FALSE; if( facilityMessage.bit_mask & alternativeAddress_present ) { if( facilityMessage.alternativeAddress.choice == ipAddress_chosen ) { pFacilityASN->AlternativeAddr.nAddrType = H323_IP_BINARY; pFacilityASN->AlternativeAddr.Addr.IP_Binary.wPort = facilityMessage.alternativeAddress.u.ipAddress.port; AddressReverseAndCopy( &(pFacilityASN->AlternativeAddr.Addr.IP_Binary.dwAddr), facilityMessage.alternativeAddress.u.ipAddress.ip.value ); pFacilityASN->fAlternativeAddressPresent = TRUE; } } if( facilityMessage.bit_mask & alternativeAliasAddress_present ) { if( !AliasAddrToAliasNames( &(pFacilityASN->pAlternativeAliasList), (PSetup_UUIE_sourceAddress) &(facilityMessage.alternativeAliasAddress) ) ) { pFacilityASN -> pAlternativeAliasList = NULL; //goto cleanup; } } if( facilityMessage.bit_mask & Facility_UUIE_conferenceID_present ) { CopyConferenceID( &pFacilityASN -> ConferenceID, &facilityMessage.conferenceID ); pFacilityASN -> ConferenceIDPresent = TRUE; } pFacilityASN->bReason = facilityMessage.reason.choice; pFacilityASN->fH245AddrPresent = FALSE; if( facilityMessage.bit_mask & Facility_UUIE_h245Address_present ) { if( facilityMessage.h245Address.choice == ipAddress_chosen ) { pFacilityASN->h245Addr.nAddrType = H323_IP_BINARY; pFacilityASN->h245Addr.Addr.IP_Binary.wPort = facilityMessage.h245Address.u.ipAddress.port; pFacilityASN->h245Addr.Addr.IP_Binary.dwAddr = ntohl( *((DWORD*)facilityMessage.h245Address.u.ipAddress.ip.value) ); pFacilityASN->fH245AddrPresent = TRUE; } } } pFacilityASN->dwH450APDUType = 0; if( (pUserInfo->h323_uu_pdu.bit_mask & h4501SupplementaryService_present) && pUserInfo->h323_uu_pdu.h4501SupplementaryService ) { pFacilityASN->dwInvokeID = 0; if( !HandleH450APDU( pUserInfo->h323_uu_pdu.h4501SupplementaryService, &pFacilityASN->dwH450APDUType, &pFacilityASN->dwInvokeID, NULL ) ) { goto cleanup; } } if( pUserInfo->h323_uu_pdu.bit_mask & h245Control_present ) { if( pUserInfo->h323_uu_pdu.h245Control != NULL ) { pFacilityASN->pH245PDU.value = new BYTE[pUserInfo->h323_uu_pdu.h245Control->value.length]; if( pFacilityASN->pH245PDU.value != NULL ) { CopyMemory( (PVOID)pFacilityASN->pH245PDU.value, (PVOID)pUserInfo->h323_uu_pdu.h245Control->value.value, pUserInfo->h323_uu_pdu.h245Control->value.length ); } pFacilityASN->pH245PDU.length = pUserInfo->h323_uu_pdu.h245Control->value.length; } } ASN1_FreeDecoded( m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); H323DBG((DEBUG_LEVEL_TRACE, "ParseFacilityASN exited: %p.", this )); return TRUE; cleanup: if( pFacilityASN -> pAlternativeAliasList != NULL ) { FreeAliasNames( pFacilityASN -> pAlternativeAliasList ); pFacilityASN -> pAlternativeAliasList = NULL; } if( pFacilityASN->fNonStandardDataPresent != NULL ) { delete pFacilityASN->nonStandardData.sData.pOctetString; pFacilityASN->nonStandardData.sData.pOctetString = NULL; pFacilityASN->fNonStandardDataPresent = NULL; } ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); return FALSE; } //!!aleways called in a lock BOOL CH323Call::ParseSetupASN( IN BYTE *pEncodedBuf, IN DWORD dwEncodedLength, OUT Q931_SETUP_ASN *pSetupASN, OUT DWORD* pdwH450APDUType ) { H323_UserInformation *pUserInfo; HRESULT hr; int iResult; DWORD dwInvokeID = 0; H323DBG((DEBUG_LEVEL_TRACE, "ParseSetupASN entered: %p.", this )); memset( (PVOID)pSetupASN, 0, sizeof(Q931_SETUP_ASN)); iResult = DecodeASN((void **) &pUserInfo, H323_UserInformation_PDU, pEncodedBuf, dwEncodedLength); if (ASN1_FAILED(iResult) || (pUserInfo == NULL)) { return FALSE; } Setup_UUIE & setupMessage = pUserInfo->h323_uu_pdu.h323_message_body.u.setup; // validate that the PDU user-data uses ASN encoding. if( (pUserInfo->bit_mask & user_data_present) && (pUserInfo->user_data.protocol_discriminator != USE_ASN1_ENCODING) ) { //log goto cleanup; } // validate that the PDU is H323 Setup information. if( pUserInfo->h323_uu_pdu.h323_message_body.choice != setup_chosen ) { //log goto cleanup; } // make sure that the conference id is formed correctly. if (setupMessage.conferenceID.length > sizeof(setupMessage.conferenceID.value)) { goto cleanup; } // parse the message contained in pUserInfo. pSetupASN->sourceAddr.bMulticast = FALSE; pSetupASN->callerAddr.bMulticast = FALSE; pSetupASN->calleeDestAddr.bMulticast = FALSE; pSetupASN->calleeAddr.bMulticast = FALSE; // no validation of sourceInfo needed. //copy thevendor info pSetupASN->EndpointType.pVendorInfo = NULL; if( setupMessage.sourceInfo.bit_mask & vendor_present ) { if( !ParseVendorInfo( &pSetupASN->VendorInfo, &setupMessage.sourceInfo.vendor) ) { goto cleanup; } pSetupASN->EndpointType.pVendorInfo = &(pSetupASN->VendorInfo); } pSetupASN->EndpointType.bIsTerminal = FALSE; if( setupMessage.sourceInfo.bit_mask & terminal_present ) { pSetupASN->EndpointType.bIsTerminal = TRUE; } pSetupASN->EndpointType.bIsGateway = FALSE; if( setupMessage.sourceInfo.bit_mask & gateway_present ) { pSetupASN->EndpointType.bIsGateway = TRUE; } pSetupASN->fNonStandardDataPresent = FALSE; if( pUserInfo->h323_uu_pdu.bit_mask & H323_UU_PDU_nonStandardData_present ) { if( !ParseNonStandardData( &pSetupASN -> nonStandardData, &pUserInfo->h323_uu_pdu.nonStandardData ) ) { goto cleanup; } pSetupASN->fNonStandardDataPresent = TRUE; } // parse the sourceAddress aliases here... if( setupMessage.bit_mask & sourceAddress_present ) { if( !AliasAddrToAliasNames( &(pSetupASN->pCallerAliasList), setupMessage.sourceAddress ) ) { pSetupASN->pCallerAliasList = NULL; //goto cleanup; } } // parse the destinationAddress aliases here... if( (setupMessage.bit_mask & destinationAddress_present) && setupMessage.destinationAddress ) { if( !AliasAddrToAliasNames( &(pSetupASN->pCalleeAliasList), (PSetup_UUIE_sourceAddress)setupMessage.destinationAddress) ) { pSetupASN->pCalleeAliasList = NULL; //goto cleanup; } } // parse the destExtraCallInfo aliases here... if( (setupMessage.bit_mask & Setup_UUIE_destExtraCallInfo_present) && setupMessage.destExtraCallInfo ) { if( !AliasAddrToAliasNames(&(pSetupASN->pExtraAliasList), (PSetup_UUIE_sourceAddress)setupMessage.destExtraCallInfo) ) { pSetupASN->pExtraAliasList = NULL; //goto cleanup; } } // parse the remoteExtensionAddress aliases here... if( setupMessage.bit_mask & Setup_UUIE_remoteExtensionAddress_present ) { pSetupASN->pExtensionAliasItem = new H323_ALIASITEM; if( pSetupASN->pExtensionAliasItem == NULL ) { goto cleanup; } hr = AliasAddrToAliasItem(pSetupASN->pExtensionAliasItem, &(setupMessage.remoteExtensionAddress)); if( hr == E_OUTOFMEMORY ) { goto cleanup; } } pSetupASN -> fCalleeDestAddrPresent = FALSE; if( setupMessage.bit_mask & Setup_UUIE_destCallSignalAddress_present ) { if( setupMessage.destCallSignalAddress.choice != ipAddress_chosen ) { goto cleanup; } pSetupASN->calleeDestAddr.nAddrType = H323_IP_BINARY; pSetupASN->calleeDestAddr.Addr.IP_Binary.wPort = setupMessage.destCallSignalAddress.u.ipAddress.port; AddressReverseAndCopy( &(pSetupASN->calleeDestAddr.Addr.IP_Binary.dwAddr), setupMessage.destCallSignalAddress.u.ipAddress.ip.value ); pSetupASN -> fCalleeDestAddrPresent = TRUE; } pSetupASN->fSourceAddrPresent = FALSE; if( setupMessage.bit_mask & sourceCallSignalAddress_present ) { if( setupMessage.sourceCallSignalAddress.choice != ipAddress_chosen ) { goto cleanup; } pSetupASN->sourceAddr.nAddrType = H323_IP_BINARY; pSetupASN->sourceAddr.Addr.IP_Binary.wPort = setupMessage.sourceCallSignalAddress.u.ipAddress.port; pSetupASN->sourceAddr.Addr.IP_Binary.dwAddr = ntohl( *((DWORD*) setupMessage.sourceCallSignalAddress.u.ipAddress.ip.value) ); pSetupASN->fSourceAddrPresent = TRUE; } pSetupASN->bCallerIsMC = setupMessage.activeMC; pSetupASN -> fFastStartPresent = FALSE; if( (setupMessage.bit_mask & Setup_UUIE_fastStart_present) && setupMessage.fastStart ) { pSetupASN->pFastStart = CopyFastStart( setupMessage.fastStart ); if( pSetupASN->pFastStart != NULL ) { pSetupASN -> fFastStartPresent = TRUE; } } CopyConferenceID (&pSetupASN -> ConferenceID, &setupMessage.conferenceID); //copy the call identifier pSetupASN -> fCallIdentifierPresent = FALSE; if( setupMessage.bit_mask & Setup_UUIE_callIdentifier_present ) { pSetupASN -> fCallIdentifierPresent = TRUE; CopyMemory( (PVOID)&(pSetupASN->callIdentifier), setupMessage.callIdentifier.guid.value, sizeof(GUID) ); } if( pUserInfo->h323_uu_pdu.h245Tunneling ) { if( m_dwOrigin == LINECALLORIGIN_INBOUND ) { //the remote endpoint has sent a tunneling proposal m_fh245Tunneling |= REMOTE_H245_TUNNELING; } else { //the msp has enabled tunneling in ReadyToInitiate messsage m_fh245Tunneling |= LOCAL_H245_TUNNELING; } } pSetupASN->wGoal = (WORD)setupMessage.conferenceGoal.choice; pSetupASN->wCallType = setupMessage.callType.choice; *pdwH450APDUType = 0; if( (pUserInfo->h323_uu_pdu.bit_mask & h4501SupplementaryService_present) && pUserInfo->h323_uu_pdu.h4501SupplementaryService ) { if( !HandleH450APDU( pUserInfo->h323_uu_pdu.h4501SupplementaryService, pdwH450APDUType, &dwInvokeID, pSetupASN ) ) { goto cleanup; } } // Free the PDU data. ASN1_FreeDecoded( m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "ParseSetupASN exited: %p.", this )); return TRUE; cleanup: FreeSetupASN( pSetupASN ); ASN1_FreeDecoded(m_ASNCoderInfo.pDecInfo, pUserInfo, H323_UserInformation_PDU); return FALSE; } //----------------------------------------------------------------------------- //GLOBAL CALLBACK FUNCTIONS CALLED BY THREAD POOL //----------------------------------------------------------------------------- // static void NTAPI CH323Call::IoCompletionCallback( IN DWORD dwStatus, IN DWORD dwBytesTransferred, IN OVERLAPPED * pOverlapped ) { CALL_OVERLAPPED *pCallOverlapped; CH323Call* pCall; H323DBG(( DEBUG_LEVEL_TRACE, "CH323Call-IoCompletionCallback entered." )); _ASSERTE (pOverlapped); pCallOverlapped = CONTAINING_RECORD( pOverlapped, CALL_OVERLAPPED, Overlapped ); pCall = pCallOverlapped -> pCall; switch (pCallOverlapped -> Type) { case OVERLAPPED_TYPE_SEND: pCall -> OnWriteComplete( dwStatus, static_cast(pCallOverlapped) ); break; case OVERLAPPED_TYPE_RECV: pCallOverlapped -> BytesTransferred = dwBytesTransferred; pCall -> OnReadComplete( dwStatus, static_cast(pCallOverlapped) ); break; default: _ASSERTE(FALSE); } H323DBG(( DEBUG_LEVEL_TRACE, "CH323Call-IoCompletionCallback exited." )); } void CH323Call::OnWriteComplete( IN DWORD dwStatus, IN CALL_SEND_CONTEXT * pSendContext ) { H323DBG(( DEBUG_LEVEL_TRACE, "OnWriteComplete entered:%p.",this )); Lock(); _ASSERTE( m_IoRefCount != 0 ); m_IoRefCount--; H323DBG((DEBUG_LEVEL_TRACE, "WriteComplete:m_IoRefCount: %d:%p.", m_IoRefCount, this )); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { if( m_IoRefCount == 0 ) { QueueTAPICallRequest( TSPI_DELETE_CALL, NULL ); H323DBG((DEBUG_LEVEL_TRACE, "call delete:%p.", this )); } } else if( dwStatus == ERROR_SUCCESS ) { if( IsInList( &m_sendBufList, &pSendContext->ListEntry ) ) { RemoveEntryList( &pSendContext->ListEntry ); delete pSendContext->WSABuf.buf; delete pSendContext; } } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "OnWriteComplete exited:%p.",this )); } void CH323Call::OnReadComplete( IN DWORD dwStatus, IN CALL_RECV_CONTEXT * pRecvContext ) { H323DBG(( DEBUG_LEVEL_TRACE, "OnReadComplete entered:%p.",this )); Lock(); _ASSERTE( m_IoRefCount != 0 ); m_IoRefCount --; H323DBG(( DEBUG_LEVEL_TRACE, "RecvBuffer:m_IoRefCount:%d:%p.", m_IoRefCount, this )); if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { if( m_IoRefCount == 0 ) { QueueTAPICallRequest( TSPI_DELETE_CALL, NULL ); H323DBG((DEBUG_LEVEL_TRACE, "call delete:%p.", this )); } } else { if( dwStatus == ERROR_SUCCESS ) { _ASSERTE( m_pRecvBuffer == pRecvContext ); if( pRecvContext->BytesTransferred == 0 ) { CloseCall( 0 ); H323DBG((DEBUG_LEVEL_TRACE, "0 bytes recvd:%p.", this )); } else { ReadEvent( pRecvContext->BytesTransferred ); } } } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "OnReadComplete exited:%p.",this )); } // static void NTAPI CH323Call::SetupSentTimerCallback( IN PVOID Parameter1, IN BOOLEAN bTimer ) { PH323_CALL pCall = NULL; //if the timer expired _ASSERTE( bTimer ); H323DBG(( DEBUG_LEVEL_TRACE, "Q931 setup expired event recvd." )); pCall=g_pH323Line -> FindH323CallAndLock((HDRVCALL) Parameter1); if( pCall != NULL ) { pCall -> SetupSentTimerExpired(); pCall -> Unlock(); } } // static void NTAPI CH323Call::CheckRestrictionTimerCallback( IN PVOID Parameter1, IN BOOLEAN bTimer ) { //if the timer expired _ASSERTE( bTimer ); H323DBG(( DEBUG_LEVEL_TRACE, "CheckRestrictionTimerCallback entered." )); if(!QueueTAPILineRequest( TSPI_CLOSE_CALL, (HDRVCALL) Parameter1, NULL, LINEDISCONNECTMODE_NOANSWER, NULL) ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not post H323 close event." )); } H323DBG(( DEBUG_LEVEL_TRACE, "CheckRestrictionTimerCallback exited." )); } // static void NTAPI CH323Call::CallReroutingTimerCallback( IN PVOID Parameter1, IN BOOLEAN bTimer ) { //If the timer expired _ASSERTE( bTimer ); H323DBG(( DEBUG_LEVEL_TRACE, "CallReroutingTimerCallback entered." )); if(!QueueTAPILineRequest( TSPI_CLOSE_CALL, (HDRVCALL) Parameter1, NULL, LINEDISCONNECTMODE_NOANSWER, NULL) ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not post H323 close event." )); } H323DBG(( DEBUG_LEVEL_TRACE, "CallReroutingTimerCallback exited." )); } //----------------------------------------------------------------------------- //CALL DIVERSION (H450.3) ENCODE/DECODE ROUTINES //----------------------------------------------------------------------------- BOOL CH323Call::HandleH450APDU( IN PH323_UU_PDU_h4501SupplementaryService pH450APDU, IN DWORD* pdwH450APDUType, OUT DWORD* pdwInvokeID, IN Q931_SETUP_ASN* pSetupASN ) { BOOL retVal = TRUE; H4501SupplementaryService * pH450APDUStruct = NULL; ServiceApdus_rosApdus * pROSApdu = NULL; int iResult; BYTE pEncodedArg[H450_ENCODED_ARG_LEN]; DWORD dwEncodedArgLen; DWORD dwOpcode; H323DBG(( DEBUG_LEVEL_TRACE, "HandleH450APDU entered:%p.", this )); //right now assuming that only one APDU is passed at a time iResult = DecodeH450ASN( (void **) &pH450APDUStruct, H4501SupplementaryService_PDU, pH450APDU->value.value, pH450APDU->value.length ); if( ASN1_FAILED(iResult) || (pH450APDUStruct == NULL) ) { return FALSE; } if( pH450APDUStruct->serviceApdu.choice != rosApdus_chosen ) { ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); return FALSE; } pROSApdu = pH450APDUStruct->serviceApdu.u.rosApdus; switch( pROSApdu->value.choice ) { case H4503ROS_invoke_chosen: if( (pROSApdu->value.u.invoke.opcode.choice != local_chosen) || (pROSApdu->value.u.invoke.argument.length > H450_ENCODED_ARG_LEN) ) { ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); return FALSE; } *pdwInvokeID = pROSApdu->value.u.invoke.invokeId; dwEncodedArgLen = pROSApdu->value.u.invoke.argument.length; CopyMemory( (PVOID)pEncodedArg, (PVOID)pROSApdu->value.u.invoke.argument.value, dwEncodedArgLen ); dwOpcode = pROSApdu->value.u.invoke.opcode.u.local; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); *pdwH450APDUType = dwOpcode; switch( dwOpcode ) { case CALLREROUTING_OPCODE: retVal = HandleCallRerouting( pEncodedArg, dwEncodedArgLen ); break; case DIVERTINGLEGINFO1_OPCODE: retVal = HandleDiversionLegInfo1( pEncodedArg, dwEncodedArgLen ); break; case DIVERTINGLEGINFO2_OPCODE: retVal = HandleDiversionLegInfo2( pEncodedArg, dwEncodedArgLen ); break; case DIVERTINGLEGINFO3_OPCODE: //Don't bail out even if this function fails. HandleDiversionLegInfo3( pEncodedArg, dwEncodedArgLen ); break; case CHECKRESTRICTION_OPCODE: if( pSetupASN == NULL ) { retVal = FALSE; } else { retVal = HandleCheckRestriction( pEncodedArg, dwEncodedArgLen, pSetupASN ); } if( retVal ) { retVal = SendQ931Message( *pdwInvokeID, 0, 0, CONNECTMESSAGETYPE, H450_RETURNRESULT|CHECKRESTRICTION_OPCODE ); } break; case CTIDENTIFY_OPCODE: retVal = HandleCTIdentify( *pdwInvokeID ); m_dwInvokeID = *pdwInvokeID; break; case CTINITIATE_OPCODE: retVal = HandleCTInitiate( pEncodedArg, dwEncodedArgLen ); m_dwInvokeID = *pdwInvokeID; break; case CTSETUP_OPCODE: retVal = HandleCTSetup( pEncodedArg, dwEncodedArgLen ); m_dwInvokeID = *pdwInvokeID; break; case HOLDNOTIFIC_OPCODE: //local hold request from the remote endpoint if( m_dwCallState != LINECALLSTATE_ONHOLD ) { SendMSPMessage( SP_MSG_Hold, 0, 1, NULL ); ChangeCallState( LINECALLSTATE_ONHOLD, 0 ); } break; case RETRIEVENOTIFIC_OPCODE: //local retrieve request from the remote endpoint if( (m_dwCallState == LINECALLSTATE_ONHOLD) && !(m_dwFlags & TSPI_CALL_LOCAL_HOLD) ) { SendMSPMessage( SP_MSG_Hold, 0, 0, NULL ); ChangeCallState( LINECALLSTATE_CONNECTED, 0 ); } break; case REMOTEHOLD_OPCODE: //remote hold request from remote endpoint if( m_dwCallState != LINECALLSTATE_ONHOLD ) { SendMSPMessage( SP_MSG_Hold, 0, 1, NULL ); ChangeCallState( LINECALLSTATE_ONHOLD, 0 ); retVal = SendQ931Message( *pdwInvokeID, 0, 0, FACILITYMESSAGETYPE, REMOTEHOLD_OPCODE| H450_RETURNRESULT ); } break; case REMOTERETRIEVE_OPCODE: //remote retrieve request from remote endpoint if( m_dwCallState == LINECALLSTATE_ONHOLD ) { SendMSPMessage( SP_MSG_Hold, 0, 0, NULL ); ChangeCallState( LINECALLSTATE_CONNECTED, 0 ); retVal = SendQ931Message( *pdwInvokeID, 0, 0, FACILITYMESSAGETYPE, REMOTERETRIEVE_OPCODE| H450_RETURNRESULT ); } break; default: _ASSERTE( 0 ); return FALSE; } break; case H4503ROS_returnResult_chosen: *pdwH450APDUType = H4503_DUMMYTYPERETURNRESULT_APDU; *pdwInvokeID = pH450APDUStruct->serviceApdu.u.rosApdus->value.u.returnResult.invokeId; retVal = HandleReturnResultDummyType( pH450APDUStruct ); // Free the PDU data. ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); break; case H4503ROS_returnError_chosen: *pdwH450APDUType = H4503_RETURNERROR_APDU; *pdwInvokeID = pH450APDUStruct->serviceApdu.u.rosApdus->value.u.returnError.invokeId; retVal = HandleReturnError( pH450APDUStruct ); // Free the PDU data. ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); break; case reject_chosen: *pdwH450APDUType = H4503_REJECT_APDU; *pdwInvokeID = pH450APDUStruct->serviceApdu.u.rosApdus->value.u.reject.invokeId; retVal = HandleReject( pH450APDUStruct ); // Free the PDU data. ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); break; default: _ASSERTE( 0 ); ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pH450APDUStruct, H4501SupplementaryService_PDU ); return FALSE; break; } if( retVal == FALSE ) { SendQ931Message( *pdwInvokeID, 0, 0, RELEASECOMPLMESSAGETYPE, H450_REJECT ); } H323DBG(( DEBUG_LEVEL_TRACE, "HandleH450APDU exited:%p.", this )); return retVal; } BOOL CH323Call::HandleReturnError( IN H4501SupplementaryService * pH450APDUStruct ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleReturnError entered:%p.", this )); ReturnError * pReturnError = &(pH450APDUStruct->serviceApdu.u.rosApdus->value.u.returnError); if( IsValidInvokeID( pReturnError->invokeId ) == FALSE ) { //ignore APDU return TRUE; } CloseCall( 0 ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleReturnError exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleReject( IN H4501SupplementaryService * pH450APDUStruct ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleReject entered:%p.", this )); Reject * pReject = &(pH450APDUStruct->serviceApdu.u.rosApdus->value.u.reject); if( IsValidInvokeID( pReject->invokeId ) == FALSE ) { //ignore the APDU return TRUE; } CloseCall( 0 ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleReject exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleReturnResultDummyType( IN H4501SupplementaryService * pH450APDUStruct ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleReturnResultDummyType entered:%p.", this )); ReturnResult* dummyResult = &(pH450APDUStruct->serviceApdu.u.rosApdus->value.u.returnResult); if( dummyResult->bit_mask & result_present ) { if( dummyResult->result.opcode.choice != local_chosen ) { return FALSE; } switch( dummyResult->result.opcode.u.local ) { case CHECKRESTRICTION_OPCODE: //forwarding has been enabled. inform the user if( !EnableCallForwarding() ) { return FALSE; } //close the call CloseCall( 0 ); break; case CALLREROUTING_OPCODE: //call has been rerouted. log the info or inform the user m_dwCallDiversionState = H4503_CALLREROUTING_RRSUCC; _ASSERTE( m_hCallReroutingTimer ); if( m_hCallReroutingTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCallReroutingTimer, NULL ); m_hCallReroutingTimer = NULL; } break; case CTIDENTIFY_OPCODE: //call tranfer has been accepted by transfered-to endpoint m_dwCallDiversionState = H4502_CIIDENTIFY_RRSUCC; _ASSERTE( m_hCTIdentifyTimer ); if( m_hCTIdentifyTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCTIdentifyTimer, NULL ); m_hCTIdentifyTimer = NULL; } return HandleCTIdentifyReturnResult( dummyResult->result.result.value, dummyResult->result.result.length ); break; case CTINITIATE_OPCODE: _ASSERTE( m_hCTInitiateTimer ); if( m_hCTInitiateTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCTInitiateTimer, NULL ); m_hCTInitiateTimer = NULL; } break; case CTSETUP_OPCODE: case REMOTEHOLD_OPCODE: case REMOTERETRIEVE_OPCODE: //no processing required break; default: H323DBG(( DEBUG_LEVEL_ERROR, "wrong opcode.", dummyResult->result.opcode.u.local )); break; } } else if( IsValidInvokeID( dummyResult->invokeId ) == FALSE ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "HandleReturnResultDummyType exited:%p.", this )); return TRUE; } BOOL CH323Call::EnableCallForwarding() { m_dwCallDiversionState = H4503_CHECKRESTRICTION_SUCC; if( m_pCallForwardParams != NULL ) { g_pH323Line->SetCallForwardParams( m_pCallForwardParams ); m_pCallForwardParams = NULL; } else if( m_pForwardAddress != NULL ) { if( !g_pH323Line->SetCallForwardParams( m_pForwardAddress ) ) { return FALSE; } m_pForwardAddress = NULL; } //_ASSERTE( m_hCheckRestrictionTimer ); //stop the timer if( m_hCheckRestrictionTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCheckRestrictionTimer, NULL ); m_hCheckRestrictionTimer = NULL; } //inform the user about change in line forward state (*g_pfnLineEventProc)( g_pH323Line->m_htLine, (HTAPICALL)NULL, (DWORD)LINE_ADDRESSSTATE, (DWORD)LINEADDRESSSTATE_FORWARD, (DWORD)LINEADDRESSSTATE_FORWARD, (DWORD)0 ); return TRUE; } BOOL CH323Call::HandleCTIdentifyReturnResult( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { PH323_CALL pCall = NULL; CTIdentifyRes * pCTIdentifyRes; int iResult; H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTIdentifyReturnResult entered:%p.", this )); if( (pEncodeArg == NULL) || (dwEncodedArgLen==0) ) { return FALSE; } iResult = DecodeH450ASN( (void **) &pCTIdentifyRes, CTIdentifyRes_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (pCTIdentifyRes == NULL) ) { return FALSE; } //send a CTInitiate message on the primary call if( !QueueSuppServiceWorkItem( SEND_CTINITIATE_MESSAGE, m_hdRelatedCall, (ULONG_PTR)pCTIdentifyRes )) { //close the consultation call. CloseCall( 0 ); } H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTIdentifyReturnResult exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleCTIdentify( IN DWORD dwInvokeID ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTIdentify entered:%p.", this )); BOOL retVal = TRUE; //send the return result for CTIdentify retVal = SendQ931Message( dwInvokeID, 0, 0, FACILITYMESSAGETYPE, H450_RETURNRESULT|CTIDENTIFY_OPCODE ); m_dwCallType |= CALLTYPE_TRANSFERED2_CONSULT; //start the timer for CTIdenity message if( retVal ) { retVal = CreateTimerQueueTimer( &m_hCTIdentifyRRTimer, H323TimerQueue, CH323Call::CTIdentifyRRExpiredCallback, (PVOID)m_hdCall, CTIDENTIFYRR_SENT_TIMEOUT, 0, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ); } H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTIdentify exited:%p.", this )); return retVal; } BOOL CH323Call::HandleCTInitiate( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTInitiate entered:%p.", this )); CTInitiateArg * pCTInitiateArg; int iResult = DecodeH450ASN( (void **) &pCTInitiateArg, CTInitiateArg_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (pCTInitiateArg == NULL) ) { return FALSE; } //argument.callIdentity CopyMemory( (PVOID)m_pCTCallIdentity, pCTInitiateArg->callIdentity, sizeof(m_pCTCallIdentity) ); //argument.reroutingNumber if( !AliasAddrToAliasNames( &m_pTransferedToAlias, (PSetup_UUIE_sourceAddress) pCTInitiateArg->reroutingNumber.destinationAddress ) ) { goto cleanup; } m_dwCallType |= CALLTYPE_TRANSFERED_PRIMARY; m_dwCallDiversionState = H4502_CTINITIATE_RECV; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCTInitiateArg, CTInitiateArg_PDU ); //queue an event for creating a new call if( !QueueSuppServiceWorkItem( TSPI_DIAL_TRNASFEREDCALL, m_hdCall, (ULONG_PTR)m_pTransferedToAlias )) { H323DBG(( DEBUG_LEVEL_TRACE, "could not post dial transfer event." )); } H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTInitiate exited:%p.", this )); return TRUE; cleanup: ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCTInitiateArg, CTInitiateArg_PDU ); return FALSE; } //!!always called in a lock BOOL CH323Call::HandleCTSetup( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { PH323_CALL pCall = NULL; WORD wRelatedCallRef = 0; int iCTCallID; H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTSetup entered:%p.", this )); CTSetupArg * pCTSetupArg; int iResult = DecodeH450ASN( (void **) &pCTSetupArg, CTSetupArg_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (pCTSetupArg == NULL) ) { return FALSE; } m_dwCallType |= CALLTYPE_TRANSFEREDDEST; m_dwCallDiversionState = H4502_CTSETUP_RECV; iCTCallID = atoi( pCTSetupArg->callIdentity ); if( iCTCallID != 0 ) { m_hdRelatedCall = g_pH323Line -> GetCallFromCTCallIdentity( iCTCallID ); if( m_hdRelatedCall ) { if( !QueueSuppServiceWorkItem( STOP_CTIDENTIFYRR_TIMER, m_hdRelatedCall, (ULONG_PTR)m_hdCall )) { m_hdRelatedCall = NULL; } } } ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCTSetupArg, CTSetupArg_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleCTSEtup exited:%p.", this )); return TRUE; } BOOL CH323Call::HandleCheckRestriction( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen, IN Q931_SETUP_ASN* pSetupASN ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleCheckRestriction entered:%p.", this )); CheckRestrictionArgument * pCheckRestriction; int iResult = DecodeH450ASN( (void **) &pCheckRestriction, CheckRestrictionArgument_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (pCheckRestriction == NULL) ) { return FALSE; } if( pSetupASN->pCalleeAliasList != NULL ) { FreeAliasNames( pSetupASN->pCalleeAliasList ); pSetupASN->pCalleeAliasList = NULL; } if( !AliasAddrToAliasNames( &(pSetupASN->pCalleeAliasList), (PSetup_UUIE_sourceAddress)pCheckRestriction->divertedToNr.destinationAddress ) ) { pSetupASN->pCalleeAliasList = NULL; goto cleanup; } if( pSetupASN->pCallerAliasList != NULL ) { FreeAliasNames( pSetupASN->pCallerAliasList ); pSetupASN->pCallerAliasList = NULL; } if( !AliasAddrToAliasNames( &(pSetupASN->pCallerAliasList), (PSetup_UUIE_sourceAddress) pCheckRestriction->servedUserNr.destinationAddress ) ) { pSetupASN->pCallerAliasList = NULL; goto cleanup; } m_dwCallType |= CALLTYPE_FORWARDCONSULT; if( !InitializeIncomingCall( pSetupASN, CALLTYPE_FORWARDCONSULT, 0 ) ) { goto cleanup; } FreeSetupASN( pSetupASN ); m_dwStateMachine = Q931_SETUP_RECVD; m_dwCallDiversionState = H4503_CHECKRESTRICTION_RECV; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCheckRestriction, CheckRestrictionArgument_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleCheckRestriction exited:%p.", this )); return TRUE; cleanup: ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCheckRestriction, CheckRestrictionArgument_PDU ); return FALSE; } BOOL CH323Call::HandleDiversionLegInfo1( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleDiversionLegInfo1 entered:%p.", this )); DivertingLegInformation1Argument * plegInfo1Invoke; int iResult = DecodeH450ASN( (void **) &plegInfo1Invoke, DivertingLegInformation1Argument_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (plegInfo1Invoke == NULL) ) { return FALSE; } if( m_pCallReroutingInfo == NULL ) { m_pCallReroutingInfo = new CALLREROUTINGINFO; if( m_pCallReroutingInfo == NULL ) { return FALSE; } ZeroMemory( (PVOID)m_pCallReroutingInfo, sizeof(CALLREROUTINGINFO) ); } m_pCallReroutingInfo->diversionReason = plegInfo1Invoke->diversionReason; m_pCallReroutingInfo->fPresentAllow = plegInfo1Invoke->subscriptionOption; //argument.divertedToNr if( m_pCallReroutingInfo->divertedToNrAlias != NULL ) { FreeAliasNames( m_pCallReroutingInfo->divertedToNrAlias ); m_pCallReroutingInfo->divertedToNrAlias = NULL; } if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->divertedToNrAlias), (PSetup_UUIE_sourceAddress) (plegInfo1Invoke->nominatedNr.destinationAddress) ) ) { goto cleanup; } m_dwCallType |= CALLTYPE_DIVERTEDSRC_NOROUTING; m_dwCallDiversionState = H4503_DIVERSIONLEG1_RECVD; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, plegInfo1Invoke, DivertingLegInformation1Argument_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleDiversionLegInfo1 exited:%p.", this )); return TRUE; cleanup: ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, plegInfo1Invoke, DivertingLegInformation1Argument_PDU ); FreeCallReroutingInfo(); return FALSE; } BOOL CH323Call::HandleDiversionLegInfo2( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleDiversionLegInfo2 entered:%p.", this )); DivertingLegInformation2Argument * plegInfo2Invoke; int iResult = DecodeH450ASN( (void **) &plegInfo2Invoke, DivertingLegInformation2Argument_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (plegInfo2Invoke == NULL) ) { return FALSE; } _ASSERTE(!m_pCallReroutingInfo); m_pCallReroutingInfo = new CALLREROUTINGINFO; if( m_pCallReroutingInfo == NULL ) { H323DBG(( DEBUG_LEVEL_TRACE, "memory failure." )); goto cleanup; } ZeroMemory( (PVOID)m_pCallReroutingInfo, sizeof(CALLREROUTINGINFO) ); //argument.diversionCounter m_pCallReroutingInfo->diversionCounter = plegInfo2Invoke->diversionCounter; //argument.diversionReason m_pCallReroutingInfo->diversionReason = plegInfo2Invoke->diversionReason; if( m_pCallReroutingInfo->divertingNrAlias != NULL ) { FreeAliasNames( m_pCallReroutingInfo->divertingNrAlias ); m_pCallReroutingInfo->divertingNrAlias = NULL; } if( (plegInfo2Invoke->bit_mask & divertingNr_present ) && plegInfo2Invoke->divertingNr.destinationAddress ) { //argument.divertingNr if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->divertingNrAlias), (PSetup_UUIE_sourceAddress) (plegInfo2Invoke->divertingNr.destinationAddress) ) ) { H323DBG(( DEBUG_LEVEL_TRACE, "no divertingnr alias." )); //goto cleanup; } } //argument.originalCalledNr if( (plegInfo2Invoke->bit_mask & DivertingLegInformation2Argument_originalCalledNr_present ) && plegInfo2Invoke->originalCalledNr.destinationAddress ) { if( m_pCallReroutingInfo->originalCalledNr != NULL ) { FreeAliasNames( m_pCallReroutingInfo->originalCalledNr ); m_pCallReroutingInfo->originalCalledNr = NULL; } if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->originalCalledNr), (PSetup_UUIE_sourceAddress) (plegInfo2Invoke->originalCalledNr.destinationAddress)) ) { H323DBG(( DEBUG_LEVEL_TRACE, "no originalcalled alias." )); //goto cleanup; } } m_dwCallType |= CALLTYPE_DIVERTEDDEST; m_dwCallDiversionState = H4503_DIVERSIONLEG2_RECVD; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, plegInfo2Invoke, DivertingLegInformation2Argument_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleDiversionLegInfo2 exited:%p.", this )); return TRUE; cleanup: ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, plegInfo2Invoke, DivertingLegInformation2Argument_PDU ); FreeCallReroutingInfo(); return FALSE; } void CH323Call::FreeCallReroutingInfo(void) { H323DBG(( DEBUG_LEVEL_TRACE, "FreeCallReroutingInfo entered:%p.", this )); if( m_pCallReroutingInfo != NULL ) { FreeAliasNames( m_pCallReroutingInfo->divertingNrAlias ); FreeAliasNames( m_pCallReroutingInfo->originalCalledNr ); FreeAliasNames( m_pCallReroutingInfo->divertedToNrAlias ); FreeAliasNames( m_pCallReroutingInfo->diversionNrAlias ); delete m_pCallReroutingInfo; m_pCallReroutingInfo = NULL; } H323DBG(( DEBUG_LEVEL_TRACE, "FreeCallReroutingInfo exited:%p.", this )); } BOOL CH323Call::HandleDiversionLegInfo3( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleDiversionLegInfo3 entered:%p.", this )); DivertingLegInformation3Argument * plegInfo3Invoke; int iResult = DecodeH450ASN( (void **) &plegInfo3Invoke, DivertingLegInformation3Argument_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (plegInfo3Invoke == NULL) ) { return FALSE; } _ASSERTE(m_pCallReroutingInfo); m_pCallReroutingInfo-> fPresentAllow = plegInfo3Invoke->presentationAllowedIndicator; if( m_pCallReroutingInfo->diversionNrAlias ) { FreeAliasNames( m_pCallReroutingInfo->diversionNrAlias ); m_pCallReroutingInfo->diversionNrAlias = NULL; } //argument.redirectionNr if( (plegInfo3Invoke->bit_mask & redirectionNr_present ) && plegInfo3Invoke->redirectionNr.destinationAddress ) { if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->diversionNrAlias), (PSetup_UUIE_sourceAddress) (plegInfo3Invoke->redirectionNr.destinationAddress) ) ) { //goto cleanup; } } _ASSERTE( (m_dwCallType & CALLTYPE_DIVERTEDSRC ) || (m_dwCallType & CALLTYPE_DIVERTEDSRC_NOROUTING ) ); m_dwCallDiversionState = H4503_DIVERSIONLEG3_RECVD; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, plegInfo3Invoke, DivertingLegInformation3Argument_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleDiversionLegInfo3 exited:%p.", this )); return TRUE; /*cleanup: ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, plegInfo3Invoke, DivertingLegInformation3Argument_PDU ); FreeCallReroutingInfo(); return FALSE; */ } BOOL CH323Call::HandleCallRerouting( IN BYTE * pEncodeArg, IN DWORD dwEncodedArgLen ) { H323DBG(( DEBUG_LEVEL_TRACE, "HandleCallRerouting entered:%p.", this )); CallReroutingArgument* pCallReroutingInv; int iResult = DecodeH450ASN( (void **) &pCallReroutingInv, CallReroutingArgument_PDU, pEncodeArg, dwEncodedArgLen ); if( ASN1_FAILED(iResult) || (pCallReroutingInv == NULL) ) { return FALSE; } if( m_pCallReroutingInfo == NULL ) { m_pCallReroutingInfo = new CALLREROUTINGINFO; if( m_pCallReroutingInfo == NULL ) { goto cleanup; } ZeroMemory( (PVOID)m_pCallReroutingInfo, sizeof(CALLREROUTINGINFO) ); } if( pCallReroutingInv->diversionCounter > MAX_DIVERSION_COUNTER ) return FALSE; m_pCallReroutingInfo->diversionCounter = pCallReroutingInv->diversionCounter; m_pCallReroutingInfo->diversionReason = pCallReroutingInv->reroutingReason; if( pCallReroutingInv->bit_mask & originalReroutingReason_present ) { m_pCallReroutingInfo->originalDiversionReason = pCallReroutingInv->originalReroutingReason; } else { m_pCallReroutingInfo->originalDiversionReason = pCallReroutingInv->reroutingReason; } if( ( pCallReroutingInv->bit_mask & CallReroutingArgument_originalCalledNr_present ) && pCallReroutingInv->originalCalledNr.destinationAddress ) { if( m_pCallReroutingInfo->originalCalledNr != NULL ) { FreeAliasNames( m_pCallReroutingInfo->originalCalledNr ); m_pCallReroutingInfo->originalCalledNr = NULL; } if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->originalCalledNr), (PSetup_UUIE_sourceAddress) (pCallReroutingInv->originalCalledNr.destinationAddress) ) ) { //goto cleanup; } } if( m_pCallReroutingInfo->divertingNrAlias != NULL ) { FreeAliasNames( m_pCallReroutingInfo->divertingNrAlias ); m_pCallReroutingInfo->divertingNrAlias = NULL; } if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->divertingNrAlias), (PSetup_UUIE_sourceAddress) (pCallReroutingInv->lastReroutingNr.destinationAddress) ) ) { goto cleanup; } if( m_pCallReroutingInfo->divertedToNrAlias != NULL ) { FreeAliasNames( m_pCallReroutingInfo->divertedToNrAlias ); m_pCallReroutingInfo->divertedToNrAlias = NULL; } if( !AliasAddrToAliasNames( &(m_pCallReroutingInfo->divertedToNrAlias), (PSetup_UUIE_sourceAddress) (pCallReroutingInv->calledAddress.destinationAddress) ) ) { goto cleanup; } m_dwCallType |= CALLTYPE_DIVERTEDSRC; m_dwCallDiversionState = H4503_CALLREROUTING_RECVD; ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCallReroutingInv, CallReroutingArgument_PDU ); H323DBG(( DEBUG_LEVEL_TRACE, "HandleCallRerouting exited:%p.", this )); return TRUE; cleanup: ASN1_FreeDecoded( m_H450ASNCoderInfo.pDecInfo, pCallReroutingInv, CallReroutingArgument_PDU ); FreeCallReroutingInfo(); return FALSE; } BOOL CH323Call::EncodeRejectAPDU( IN H4501SupplementaryService * pSupplementaryServiceAPDU, IN DWORD dwInvokeID, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { WORD wAPDULen; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeRejectAPDU entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = reject_chosen; pROSAPDU->value.u.reject.invokeId = (WORD)dwInvokeID; pROSAPDU->value.u.reject.problem.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.reject.problem.u.invoke = InvokeProblem_mistypedArgument; //call ASN.1 encoding functions int rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wAPDULen ); *pdwAPDULen = wAPDULen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeRejectAPDU exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeReturnErrorAPDU( IN DWORD dwInvokeID, IN DWORD dwErrorCode, IN H4501SupplementaryService *pH450APDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { WORD wAPDULen; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeReturnErrorAPDU entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pH450APDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU ->value.choice = H4503ROS_returnError_chosen; pROSAPDU ->value.u.returnError.invokeId = (WORD)dwInvokeID; pROSAPDU ->value.u.returnError.errcode.choice = local_chosen; pROSAPDU ->value.u.returnError.errcode.u.local = dwErrorCode; //call ASN.1 encoding functions int rc = EncodeH450ASN( (void *) pH450APDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wAPDULen ); *pdwAPDULen = wAPDULen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeReturnErrorAPDU exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeDummyReturnResultAPDU( IN DWORD dwInvokeID, IN DWORD dwOpCode, IN H4501SupplementaryService *pH450APDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; WORD wEncodedLen = 0; int rc; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDummyReturnResultAPDU entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pH450APDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU ->value.choice = H4503ROS_returnResult_chosen; pROSAPDU ->value.u.returnResult.invokeId = (WORD)dwInvokeID; pROSAPDU ->value.u.returnResult.bit_mask = result_present; pROSAPDU ->value.u.returnResult.result.opcode.choice = local_chosen; pROSAPDU ->value.u.returnResult.result.opcode.u.local = dwOpCode; //dummy result not present pROSAPDU ->value.u.returnResult.result.result.length = 0; pROSAPDU ->value.u.returnResult.result.result.value = NULL; switch( dwOpCode ) { case CTIDENTIFY_OPCODE: pROSAPDU ->value.u.returnResult.result.result.value = pBufEncodedArg; if( !EncodeCTIdentifyReturnResult( pROSAPDU ) ) { return FALSE; } break; default: pROSAPDU ->value.u.returnResult.result.result.value = pBufEncodedArg; if( !EncodeDummyResult( pROSAPDU ) ) { return FALSE; } break; } //call ASN.1 encoding functions rc = EncodeH450ASN( (void *) pH450APDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDummyReturnResultAPDU exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeDummyResult( OUT ServiceApdus_rosApdus *pROSAPDU ) { DummyRes dummyRes; BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; int rc; UCHAR sData[3] = "MS"; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDummyResult entered:%p.", this )); ZeroMemory( (PVOID)&dummyRes, sizeof(DummyRes) ); dummyRes.choice = DummyRes_nonStandardData_chosen; dummyRes.u.nonStandardData.nonStandardIdentifier.choice = H225NonStandardIdentifier_h221NonStandard_chosen; dummyRes.u.nonStandardData.nonStandardIdentifier.u.h221NonStandard.t35CountryCode = H221_COUNTRY_CODE_USA; dummyRes.u.nonStandardData.nonStandardIdentifier.u.h221NonStandard.t35Extension = H221_COUNTRY_EXT_USA; dummyRes.u.nonStandardData.nonStandardIdentifier.u.h221NonStandard.manufacturerCode = H221_MFG_CODE_MICROSOFT; dummyRes.u.nonStandardData.data.length = 2; dummyRes.u.nonStandardData.data.value = sData; //encode the return result argument. rc = EncodeH450ASN( (void*) &dummyRes, DummyRes_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { return FALSE; } pROSAPDU ->value.u.returnResult.result.result.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU ->value.u.returnResult.result.result.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDummyResult exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeCTIdentifyReturnResult( OUT ServiceApdus_rosApdus *pROSAPDU ) { CTIdentifyRes cTIdentifyRes; BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; int iCallID; int rc; ZeroMemory( (PVOID)&cTIdentifyRes, sizeof(CTIdentifyRes) ); iCallID = g_pH323Line -> GetCTCallIdentity(m_hdCall ); if( iCallID == 0 ) { return FALSE; } //argument.callIdentity _itoa( iCallID, (char*)m_pCTCallIdentity, 10 ); CopyMemory( (PVOID)cTIdentifyRes.callIdentity, (PVOID)m_pCTCallIdentity, sizeof(m_pCTCallIdentity) ); //argument.reroutingNumber cTIdentifyRes.reroutingNumber.bit_mask = 0; cTIdentifyRes.reroutingNumber.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCalleeAliasNames ); if( cTIdentifyRes.reroutingNumber.destinationAddress == NULL ) { return FALSE; } //encode the return result argument. rc = EncodeH450ASN( (void *) &cTIdentifyRes, CTIdentifyRes_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) cTIdentifyRes.reroutingNumber.destinationAddress ); return FALSE; } pROSAPDU ->value.u.returnResult.result.result.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU ->value.u.returnResult.result.result.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); FreeAddressAliases( (PSetup_UUIE_destinationAddress) cTIdentifyRes.reroutingNumber.destinationAddress ); return TRUE; } //supplemantary services functions BOOL CH323Call::EncodeCheckRestrictionAPDU( OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; BOOL retVal = FALSE; int rc = 0; TCHAR szMsg[20]; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCheckRestrictionAPDU entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = argument_present; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); m_dwInvokeID = pROSAPDU->value.u.invoke.invokeId; //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = CHECKRESTRICTION_OPCODE; //argument CheckRestrictionArgument checkRestrictionArgument; ZeroMemory( (PVOID)&checkRestrictionArgument, sizeof(CheckRestrictionArgument) ); //argument.divertedToNR checkRestrictionArgument.divertedToNr.bit_mask = 0; checkRestrictionArgument.divertedToNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCalleeAliasNames ); if( checkRestrictionArgument.divertedToNr.destinationAddress == NULL ) { goto cleanup; } if( m_pCallerAliasNames == NULL ) { m_pCallerAliasNames = new H323_ALIASNAMES; if( m_pCallerAliasNames == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate caller name." )); goto cleanup; } memset( (PVOID)m_pCallerAliasNames, 0, sizeof(H323_ALIASNAMES) ); LoadString( g_hInstance, IDS_UNKNOWN, szMsg, 20 ); if( !AddAliasItem( m_pCallerAliasNames, szMsg, h323_ID_chosen ) ) { goto cleanup; } //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); } //argument.servedUserNR checkRestrictionArgument.servedUserNr.bit_mask = 0; checkRestrictionArgument.servedUserNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCallerAliasNames ); //H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this )); if( checkRestrictionArgument.servedUserNr.destinationAddress == NULL ) { goto cleanup; } //argument.basicservice checkRestrictionArgument.basicService = allServices; //encode the checkrestriction argument. rc = EncodeH450ASN( (void *) &checkRestrictionArgument, CheckRestrictionArgument_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { goto cleanup; } pROSAPDU->value.u.invoke.argument.value = pBufEncodedArg; pROSAPDU->value.u.invoke.argument.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU->value.u.invoke.argument.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); //call ASN.1 encoding functions rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { goto cleanup; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCheckRestrictionAPDU exited:%p.", this )); retVal = TRUE; cleanup: if( checkRestrictionArgument.servedUserNr.destinationAddress ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) checkRestrictionArgument.servedUserNr.destinationAddress ); } if( checkRestrictionArgument.divertedToNr.destinationAddress ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) checkRestrictionArgument.divertedToNr.destinationAddress ); } return retVal; } BOOL CH323Call::EncodeDivertingLeg2APDU( OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; BOOL retVal = FALSE; int rc = 0; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDivertingLeg2APDU entered:%p.", this )); pSupplementaryServiceAPDU->interpretationApdu.choice = discardAnyUnrecognizedInvokePdu_chosen; ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = argument_present; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = DIVERTINGLEGINFO2_OPCODE; //argument DivertingLegInformation2Argument divertLegInfo2Arg; ZeroMemory( (PVOID)&divertLegInfo2Arg, sizeof(DivertingLegInformation2Argument) ); //argument.diversionCounter divertLegInfo2Arg.diversionCounter = (WORD)m_pCallReroutingInfo->diversionCounter; //argument.diversionreason divertLegInfo2Arg.diversionReason = m_pCallReroutingInfo->diversionReason; //argument.originalDiversionReason if( m_pCallReroutingInfo->originalDiversionReason != 0 ) { divertLegInfo2Arg.originalDiversionReason = m_pCallReroutingInfo->originalDiversionReason; divertLegInfo2Arg.bit_mask |= originalDiversionReason_present; } //argument.divertingNr if( m_pCallReroutingInfo->divertingNrAlias != NULL ) { divertLegInfo2Arg.bit_mask |= divertingNr_present; divertLegInfo2Arg.divertingNr.bit_mask = 0; divertLegInfo2Arg.divertingNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCallReroutingInfo->divertingNrAlias ); if( divertLegInfo2Arg.divertingNr.destinationAddress == NULL ) { return FALSE; } } //argument.originalCalledNr if( m_pCallReroutingInfo->originalCalledNr != NULL ) { divertLegInfo2Arg.bit_mask |= DivertingLegInformation2Argument_originalCalledNr_present; divertLegInfo2Arg.originalCalledNr.bit_mask = 0; divertLegInfo2Arg.originalCalledNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCallReroutingInfo->originalCalledNr ); if( divertLegInfo2Arg.originalCalledNr.destinationAddress == NULL ) { goto cleanup; } } //encode the divertingleg2 argument. rc = EncodeH450ASN( (void *) &divertLegInfo2Arg, DivertingLegInformation2Argument_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { goto cleanup; } pROSAPDU->value.u.invoke.argument.value = pBufEncodedArg; pROSAPDU->value.u.invoke.argument.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU->value.u.invoke.argument.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before encoding new one ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); //call ASN.1 encoding function for APDU rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { goto cleanup; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDivertingLeg2APDU exited:%p.", this )); retVal= TRUE; cleanup: if( divertLegInfo2Arg.divertingNr.destinationAddress ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) divertLegInfo2Arg.divertingNr.destinationAddress ); } if( divertLegInfo2Arg.originalCalledNr.destinationAddress ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) divertLegInfo2Arg.originalCalledNr.destinationAddress ); } return retVal; } BOOL CH323Call::EncodeDivertingLeg3APDU( OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDivertingLeg3APDU entered:%p.", this )); pSupplementaryServiceAPDU->interpretationApdu.choice = discardAnyUnrecognizedInvokePdu_chosen; ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = argument_present; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = DIVERTINGLEGINFO3_OPCODE; //argument DivertingLegInformation3Argument divertLegInfo3Arg; ZeroMemory( (PVOID)&divertLegInfo3Arg, sizeof(DivertingLegInformation3Argument) ); //argument.presentationallowed divertLegInfo3Arg.presentationAllowedIndicator = TRUE; //argument.redirectionNr divertLegInfo3Arg.redirectionNr.bit_mask = 0; divertLegInfo3Arg.redirectionNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCalleeAliasNames ); if( divertLegInfo3Arg.redirectionNr.destinationAddress ) { divertLegInfo3Arg.bit_mask |= redirectionNr_present; } //encode the divertingleg3 argument. int rc = EncodeH450ASN( (void *) &divertLegInfo3Arg, DivertingLegInformation3Argument_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { if( divertLegInfo3Arg.redirectionNr.destinationAddress ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) divertLegInfo3Arg.redirectionNr.destinationAddress ); } return FALSE; } pROSAPDU->value.u.invoke.argument.value = pBufEncodedArg; pROSAPDU->value.u.invoke.argument.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU->value.u.invoke.argument.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before encoding new one ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); if( divertLegInfo3Arg.redirectionNr.destinationAddress ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) divertLegInfo3Arg.redirectionNr.destinationAddress ); } //call ASN.1 encoding function for APDU rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeDivertingLeg3APDU exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeCallReroutingAPDU( OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; BOOL retVal = FALSE; int rc = 0; UCHAR bearerCap[5]; TCHAR szMsg[20]; PH323_ALIASNAMES pCallerAliasNames = m_pCallerAliasNames; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCallReroutingAPDU entered:%p.", this )); _ASSERTE( m_pCallReroutingInfo ); ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = argument_present; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); m_dwInvokeID = pROSAPDU->value.u.invoke.invokeId; //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = CALLREROUTING_OPCODE; //argument CallReroutingArgument callReroutingArg; ZeroMemory( (PVOID)&callReroutingArg, sizeof(CallReroutingArgument) ); //argument.reroutingReason callReroutingArg.reroutingReason = m_pCallReroutingInfo->diversionReason; //argument.originalReroutingReason if( m_pCallReroutingInfo->originalDiversionReason != 0 ) { callReroutingArg.originalReroutingReason = m_pCallReroutingInfo->originalDiversionReason; } else { callReroutingArg.originalReroutingReason = m_pCallReroutingInfo->diversionReason; } //argument.diversionCounter callReroutingArg.diversionCounter = ++(m_pCallReroutingInfo->diversionCounter); //argument.calledAddress callReroutingArg.calledAddress.bit_mask = 0; callReroutingArg.calledAddress.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias(m_pCallReroutingInfo->divertedToNrAlias); if( callReroutingArg.calledAddress.destinationAddress == NULL ) { goto cleanup; } //argument.lastReroutingNr callReroutingArg.lastReroutingNr.bit_mask = 0; callReroutingArg.lastReroutingNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias(m_pCalleeAliasNames); if( callReroutingArg.lastReroutingNr.destinationAddress == NULL ) { goto cleanup; } //argument.subscriptionoption callReroutingArg.subscriptionOption = notificationWithDivertedToNr; //argument.callingNumber callReroutingArg.callingNumber.bit_mask = 0; if( pCallerAliasNames == NULL ) { pCallerAliasNames = new H323_ALIASNAMES; if( pCallerAliasNames == NULL ) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate caller name." )); goto cleanup; } memset( (PVOID)pCallerAliasNames, 0, sizeof(H323_ALIASNAMES) ); LoadString( g_hInstance, IDS_UNKNOWN, szMsg, 20 ); if( !AddAliasItem( pCallerAliasNames, szMsg, h323_ID_chosen ) ) { goto cleanup; } } callReroutingArg.callingNumber.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias(pCallerAliasNames); if( callReroutingArg.callingNumber.destinationAddress == NULL ) { goto cleanup; } //argumnt.h225infoelement callReroutingArg.h225InfoElement.length = 5; callReroutingArg.h225InfoElement.value = bearerCap; bearerCap[0]= IDENT_BEARERCAP; bearerCap[1]= 0x03; //length of the bearer capability bearerCap[2]= (BYTE)(BEAR_EXT_BIT | BEAR_CCITT | BEAR_UNRESTRICTED_DIGITAL); bearerCap[3]= BEAR_EXT_BIT | 0x17; bearerCap[4]= (BYTE)(BEAR_EXT_BIT | BEAR_LAYER1_INDICATOR | BEAR_LAYER1_H221_H242); //argument.callingNumber if( m_pCallReroutingInfo->originalCalledNr != NULL ) { callReroutingArg.originalCalledNr.bit_mask = 0; callReroutingArg.originalCalledNr.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pCallReroutingInfo->originalCalledNr ); if( callReroutingArg.originalCalledNr.destinationAddress != NULL ) { callReroutingArg.bit_mask |= CallReroutingArgument_originalCalledNr_present; } } //encode the callrerouting argument. rc = EncodeH450ASN( (void *) &callReroutingArg, CallReroutingArgument_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { goto cleanup; } pROSAPDU->value.u.invoke.argument.value = pBufEncodedArg; pROSAPDU->value.u.invoke.argument.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU->value.u.invoke.argument.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before encoding new one ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); //call ASN.1 encoding function for APDU rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { goto cleanup; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCallReroutingAPDU exited:%p.", this )); retVal = TRUE; cleanup: if( pCallerAliasNames != m_pCallerAliasNames ) { FreeAliasNames( pCallerAliasNames ); } FreeCallReroutingArg( &callReroutingArg ); return retVal; } //No need to call in a lock!! void CH323Call::FreeCallReroutingArg( CallReroutingArgument* pCallReroutingArg ) { //free all the aliases if( pCallReroutingArg->calledAddress.destinationAddress != NULL ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) pCallReroutingArg->calledAddress.destinationAddress ); } if( pCallReroutingArg->lastReroutingNr.destinationAddress != NULL ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) pCallReroutingArg->lastReroutingNr.destinationAddress ); } if( pCallReroutingArg->callingNumber.destinationAddress != NULL ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) pCallReroutingArg->callingNumber.destinationAddress ); } if( pCallReroutingArg->originalCalledNr.destinationAddress != NULL ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) pCallReroutingArg->originalCalledNr.destinationAddress ); } } // static void NTAPI CH323Call::CallEstablishmentExpiredCallback( IN PVOID DriverCallHandle, // HDRVCALL IN BOOLEAN bTimer) { PH323_CALL pCall = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "CallEstablishmentExpiredCallback entered." )); //if the timer expired _ASSERTE( bTimer ); H323DBG(( DEBUG_LEVEL_TRACE, "Q931 setup expired event recvd." )); pCall=g_pH323Line -> FindH323CallAndLock((HDRVCALL) DriverCallHandle); if( pCall != NULL ) { if( pCall -> GetStateMachine() != Q931_CONNECT_RECVD ) { //time out has occured pCall -> CloseCall( LINEDISCONNECTMODE_NOANSWER ); } pCall -> Unlock(); } H323DBG(( DEBUG_LEVEL_TRACE, "CallEstablishmentExpiredCallback exited." )); } //----------------------------------------------------------------------------- //CALL TRANSFER (H450.2) ENCODE/DECODE ROUTINES //----------------------------------------------------------------------------- BOOL CH323Call::EncodeH450APDUNoArgument( IN DWORD dwOpcode, OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; int rc; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeH450APDUNoArgument entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = 0; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); m_dwInvokeID = pROSAPDU->value.u.invoke.invokeId; //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = dwOpcode; //no argument passed //call ASN.1 encoding function for APDU rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeH450APDUNoArgument exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeCTInitiateAPDU( OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; int rc = 0; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCTInitiateAPDU entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = argument_present; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); m_dwInvokeID = pROSAPDU->value.u.invoke.invokeId; //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = CTINITIATE_OPCODE; //argument CTInitiateArg cTInitiateArg; ZeroMemory( (PVOID)&cTInitiateArg, sizeof(CTInitiateArg) ); //argument.callIdentity CopyMemory( (PVOID)cTInitiateArg.callIdentity, (PVOID)m_pCTCallIdentity, sizeof(m_pCTCallIdentity) ); //argument.reroutingNumber cTInitiateArg.reroutingNumber.bit_mask = 0; cTInitiateArg.reroutingNumber.destinationAddress = (PEndpointAddress_destinationAddress) SetMsgAddressAlias( m_pTransferedToAlias ); if( cTInitiateArg.reroutingNumber.destinationAddress == NULL ) { return FALSE; } //encode the CTSetup argument. rc = EncodeH450ASN( (void *) &cTInitiateArg, CTInitiateArg_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) cTInitiateArg.reroutingNumber.destinationAddress ); return FALSE; } pROSAPDU->value.u.invoke.argument.value = pBufEncodedArg; pROSAPDU->value.u.invoke.argument.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU->value.u.invoke.argument.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before encoding new one ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); FreeAddressAliases( (PSetup_UUIE_destinationAddress) cTInitiateArg.reroutingNumber.destinationAddress ); //call ASN.1 encoding function for APDU rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCTInitiateAPDU exited:%p.", this )); return TRUE; } BOOL CH323Call::EncodeCTSetupAPDU( OUT H4501SupplementaryService *pSupplementaryServiceAPDU, OUT BYTE** ppEncodedAPDU, OUT DWORD* pdwAPDULen ) { BYTE *pEncodedArg = NULL; WORD wEncodedLen = 0; BYTE pBufEncodedArg[H450_ENCODED_ARG_LEN]; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCTSetupAPDU entered:%p.", this )); ServiceApdus_rosApdus *pROSAPDU = pSupplementaryServiceAPDU->serviceApdu.u.rosApdus; pROSAPDU->next = NULL; pROSAPDU->value.choice = H4503ROS_invoke_chosen; pROSAPDU->value.u.invoke.bit_mask = argument_present; //invoke ID pROSAPDU->value.u.invoke.invokeId = g_pH323Line->GetNextInvokeID(); m_dwInvokeID = pROSAPDU->value.u.invoke.invokeId; //opcode pROSAPDU->value.u.invoke.opcode.choice = local_chosen; pROSAPDU->value.u.invoke.opcode.u.local = CTSETUP_OPCODE; //argument CTSetupArg cTSetupArg; ZeroMemory( (PVOID)&cTSetupArg, sizeof(CTSetupArg) ); //argument.callIdentity CopyMemory( (PVOID)cTSetupArg.callIdentity, (PVOID)m_pCTCallIdentity, sizeof(m_pCTCallIdentity) ); //no argument.transferingNumber //encode the CTSetup argument. int rc = EncodeH450ASN( (void *) &cTSetupArg, CTSetupArg_PDU, &pEncodedArg, &wEncodedLen ); if( ASN1_FAILED(rc) || (pEncodedArg == NULL) || (wEncodedLen == 0) ) { return FALSE; } pROSAPDU->value.u.invoke.argument.value = pBufEncodedArg; pROSAPDU->value.u.invoke.argument.length = wEncodedLen; CopyMemory( (PVOID)pROSAPDU->value.u.invoke.argument.value, pEncodedArg, wEncodedLen ); //free the previous asn buffer before encoding new one ASN1_FreeEncoded(m_ASNCoderInfo.pEncInfo, pEncodedArg ); //call ASN.1 encoding function for APDU rc = EncodeH450ASN( (void *) pSupplementaryServiceAPDU, H4501SupplementaryService_PDU, ppEncodedAPDU, &wEncodedLen ); *pdwAPDULen = wEncodedLen; if( ASN1_FAILED(rc) || (*ppEncodedAPDU == NULL) || (pdwAPDULen == 0) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "EncodeCTSetupAPDU exited:%p.", this )); return TRUE; } void CH323Call::PostLineEvent ( IN DWORD MessageID, IN DWORD_PTR Parameter1, IN DWORD_PTR Parameter2, IN DWORD_PTR Parameter3) { (*g_pfnLineEventProc) ( g_pH323Line -> m_htLine, m_htCall, MessageID, Parameter1, Parameter2, Parameter3); } //!!must be always called in a lock void CH323Call::DecrementIoRefCount( OUT BOOL * pfDelete ) { _ASSERTE( m_IoRefCount != 0 ); m_IoRefCount--; H323DBG((DEBUG_LEVEL_TRACE, "DecrementIoRefCount:m_IoRefCount:%d:%p.", m_IoRefCount, this )); *pfDelete = FALSE; if( m_dwFlags & CALLOBJECT_SHUTDOWN ) { *pfDelete = (m_IoRefCount==0) ? TRUE : FALSE; } } //!!must be always called in a lock void CH323Call::StopCTIdentifyRRTimer( HDRVCALL hdRelatedCall ) { if( m_hCTIdentifyRRTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hCTIdentifyRRTimer, NULL ); m_hCTIdentifyRRTimer = NULL; } m_hdRelatedCall = hdRelatedCall; } void CH323Call::InitializeRecvBuf() { m_RecvBuf.WSABuf.len = sizeof(TPKT_HEADER_SIZE); m_RecvBuf.WSABuf.buf = m_RecvBuf.arBuf; m_RecvBuf.dwPDULen = m_RecvBuf.dwBytesCopied = 0; m_bStartOfPDU = TRUE; } BOOL CH323Call::SetCallData( LPVOID lpCallData, DWORD dwSize ) { if( m_CallData.pOctetString != NULL ) { delete m_CallData.pOctetString; } m_CallData.pOctetString = new BYTE[dwSize]; if( m_CallData.pOctetString == NULL ) { m_CallData.wOctetStringLength = 0; return FALSE; } CopyMemory( (PVOID)m_CallData.pOctetString, lpCallData, dwSize ); m_CallData.wOctetStringLength = (WORD)dwSize; return TRUE; } // Global Functions BOOL IsPhoneNumber( char * szAddr ) { while( *szAddr ) { if( !isdigit(*szAddr) && ('#' != *szAddr) && ('*' != *szAddr) && ('+' != *szAddr) ) return FALSE; szAddr++; } return TRUE; } BOOL IsValidE164String( IN WCHAR* wszDigits ) { for( ; (*wszDigits) != L'\0'; wszDigits++ ) { if(!( ((*wszDigits >= L'0') && (*wszDigits <= L'9')) || (*wszDigits == L'*') || (*wszDigits == L'#') || (*wszDigits == L'!') || (*wszDigits == L',') )) { return FALSE; } } return TRUE; }