/*++ Copyright (c) 1999 Microsoft Corporation Module Name: ras.cpp Abstract: The RAS client functionality (Transport/session mangement) Author: Nikhil Bobde (NikhilB) Revision History: --*/ #include "globals.h" #include "q931obj.h" #include "line.h" #include "q931pdu.h" #include "ras.h" #define OID_ELEMENT_LAST(Value) { NULL, Value } #define OID_ELEMENT(Index,Value) { (ASN1objectidentifier_s *) &_OID_H225ProtocolIdentifierV1 [Index], Value }, // this stores an unrolled constant linked list const ASN1objectidentifier_s _OID_H225ProtocolIdentifierV1 [] = { OID_ELEMENT (1, 0) // 0 = ITU-T OID_ELEMENT (2, 0) // 0 = Recommendation OID_ELEMENT (3, 8) // 8 = H Series OID_ELEMENT (4, 2250) // 2250 = H.225.0 OID_ELEMENT (5, 0) // 0 = Version OID_ELEMENT_LAST (1) // 1 = V1 }; #undef OID_ELEMENT #define OID_ELEMENT(Index,Value) { (ASN1objectidentifier_s *) &_OID_H225ProtocolIdentifierV2 [Index], Value }, // this stores an unrolled constant linked list const ASN1objectidentifier_s _OID_H225ProtocolIdentifierV2 [] = { OID_ELEMENT (1, 0) // 0 = ITU-T OID_ELEMENT (2, 0) // 0 = Recommendation OID_ELEMENT (3, 8) // 8 = H Series OID_ELEMENT (4, 2250) // 2250 = H.225.0 OID_ELEMENT (5, 0) // 0 = Version OID_ELEMENT_LAST (2) // 2 = V2 }; RAS_CLIENT g_RasClient; static LONG RasSequenceNumber; PH323_ALIASNAMES RASGetRegisteredAliasList() { return g_RasClient.GetRegisteredAliasList(); } HRESULT RasStart (void) { H323DBG(( DEBUG_LEVEL_TRACE, "RasStart - entered." )); if( (g_RegistrySettings.saGKAddr.sin_addr.s_addr == NULL) || (g_RegistrySettings.saGKAddr.sin_addr.s_addr == INADDR_NONE ) ) { return E_FAIL; } if (g_RegistrySettings.fIsGKEnabled) { if( !g_RasClient.Initialize (&g_RegistrySettings.saGKAddr) ) return E_OUTOFMEMORY; //send the rrq message if( !g_RasClient.SendRRQ( NOT_RESEND_SEQ_NUM, NULL ) ) { H323DBG(( DEBUG_LEVEL_TRACE, "couldn't send rrq." )); //m_RegisterState = RAS_REGISTER_STATE_IDLE; return E_FAIL; } } H323DBG(( DEBUG_LEVEL_TRACE, "RasStart - exited." )); return S_OK; } void RasStop (void) { H323DBG(( DEBUG_LEVEL_TRACE, "RasStop - entered." )); DWORD dwState = g_RasClient.GetRegState(); if( (dwState==RAS_REGISTER_STATE_REGISTERED) || (dwState==RAS_REGISTER_STATE_RRQSENT) ) { //send urq g_RasClient.SendURQ( NOT_RESEND_SEQ_NUM, NULL ); } g_RasClient.Shutdown(); H323DBG(( DEBUG_LEVEL_TRACE, "RasStop - exited." )); } BOOL RasIsRegistered (void) { return g_RasClient.GetRegState() == RAS_REGISTER_STATE_REGISTERED; } HRESULT RasGetLocalAddress ( OUT SOCKADDR_IN * ReturnLocalAddress) { return g_RasClient.GetLocalAddress (ReturnLocalAddress); } USHORT RasAllocSequenceNumber (void) { USHORT SequenceNumber; H323DBG(( DEBUG_LEVEL_TRACE, "RasAllocSequenceNumber - entered." )); do { SequenceNumber = (USHORT) InterlockedIncrement (&RasSequenceNumber); } while( SequenceNumber == 0 ); H323DBG(( DEBUG_LEVEL_TRACE, "RasAllocSequenceNumber - exited." )); return SequenceNumber; } HRESULT RasEncodeSendMessage ( IN RasMessage * pRasMessage) { return g_RasClient.IssueSend( pRasMessage ) ? S_OK : E_FAIL; } HRESULT RasGetEndpointID ( OUT EndpointIdentifier * ReturnEndpointID) { return g_RasClient.GetEndpointID (ReturnEndpointID); } void RasHandleRegistryChange() { g_RasClient.HandleRegistryChange(); } RAS_CLIENT::RAS_CLIENT() { //create the timer queue m_hRegTimer = NULL; m_hRegTTLTimer = NULL; m_hUnRegTimer = NULL; m_RegisterState = RAS_REGISTER_STATE_IDLE; m_IoRefCount = 0; m_dwState = RAS_CLIENT_STATE_NONE; m_pAliasList = NULL; m_Socket = INVALID_SOCKET; InitializeListHead( &m_sendPendingList ); InitializeListHead( &m_sendFreeList ); InitializeListHead( &m_aliasChangeRequestList ); m_dwSendFreeLen = 0; m_lastRegisterSeqNum = 0; m_wTTLSeqNumber = 0; m_UnRegisterSeqNum = 0; m_wRASSeqNum = 0; m_dwRegRetryCount = 0; m_dwUnRegRetryCount = 0; m_dwCallsInProgress = 0; m_dwRegTimeToLive = 0; m_pRRQExpireContext = NULL; m_pURQExpireContext = NULL; ZeroMemory( (PVOID)&m_GKAddress, sizeof(SOCKADDR_IN) ); ZeroMemory( (PVOID)&m_ASNCoderInfo, sizeof(ASN1_CODER_INFO) ); ZeroMemory( (PVOID)&m_PendingURQ, sizeof(PENDINGURQ) ); ZeroMemory( (PVOID)&m_RASEndpointID, sizeof(ENDPOINT_ID) ); // No need to check the result of this one since this object is // not allocated on heap, right when the DLL is loaded. InitializeCriticalSectionAndSpinCount( &m_CriticalSection, 0x80000000 ); } RAS_CLIENT::~RAS_CLIENT (void) { //free the various lists FreeSendList( &m_sendFreeList ); FreeSendList( &m_sendPendingList ); FreeSendList( &m_aliasChangeRequestList ); DeleteCriticalSection( &m_CriticalSection ); } HRESULT RAS_CLIENT::GetEndpointID( OUT EndpointIdentifier * ReturnEndpointID ) { HRESULT hr; H323DBG(( DEBUG_LEVEL_TRACE, "GetEndpointID - entered." )); Lock(); if (m_RegisterState == RAS_REGISTER_STATE_REGISTERED) { ReturnEndpointID->length = m_RASEndpointID.length; //m_RASEndpointID.value is an array and not a pointer. //so explicit assignment of each field is required ReturnEndpointID->value = m_RASEndpointID.value; hr = S_OK; } else { hr = S_OK; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "GetEndpointID - exited." )); return hr; } //the addr and port are in network byte order BOOL RAS_CLIENT::Initialize( IN SOCKADDR_IN* psaGKAddr ) { DWORD dwSize; int rc; H323DBG(( DEBUG_LEVEL_TRACE, "RAS Initialize entered:%p.",this )); //set the m_GKAddress here dwSize = sizeof m_RASEndpointID.value; GetComputerNameW( m_RASEndpointID.value, &dwSize ); m_RASEndpointID.length = (WORD)wcslen(m_RASEndpointID.value); m_pAliasList = new H323_ALIASNAMES; if( m_pAliasList == NULL ) { goto error2; } ZeroMemory( (PVOID)m_pAliasList, sizeof(H323_ALIASNAMES) ); if( g_RegistrySettings.fIsGKLogOnPhoneEnabled ) { if(!AddAliasItem( m_pAliasList, g_RegistrySettings.wszGKLogOnPhone, e164_chosen )) { goto error3; } } if( g_RegistrySettings.fIsGKLogOnAccountEnabled ) { if(!AddAliasItem( m_pAliasList, g_RegistrySettings.wszGKLogOnAccount, h323_ID_chosen )) { goto error3; } } if( m_pAliasList->wCount == 0 ) { //add the machine name as he default alias if(!AddAliasItem( m_pAliasList, m_RASEndpointID.value, h323_ID_chosen )) { goto error3; } } rc = InitASNCoder(); if( rc != ASN1_SUCCESS ) { H323DBG((DEBUG_LEVEL_TRACE, "RAS_InitCoder() returned: %d ", rc)); goto error3; } m_GKAddress = *psaGKAddr; if(!InitializeIo() ) { goto error4; } H323DBG((DEBUG_LEVEL_TRACE, "GK addr:%lx.", m_GKAddress.sin_addr.s_addr )); m_dwState = RAS_CLIENT_STATE_INITIALIZED; m_RegisterState = RAS_REGISTER_STATE_IDLE; H323DBG(( DEBUG_LEVEL_TRACE, "RAS Initialize exited:%p.",this )); return TRUE; error4: TermASNCoder(); error3: FreeAliasNames( m_pAliasList ); m_pAliasList = NULL; error2: return FALSE; } void RAS_CLIENT::Shutdown(void) { H323DBG(( DEBUG_LEVEL_TRACE, "RAS Shutdown entered:%p.",this )); Lock(); switch (m_dwState) { case RAS_CLIENT_STATE_NONE: // nothing to do break; case RAS_CLIENT_STATE_INITIALIZED: if( m_Socket != INVALID_SOCKET ) { closesocket(m_Socket); m_Socket = INVALID_SOCKET; } //free alias list FreeAliasNames( m_pAliasList ); m_pAliasList = NULL; TermASNCoder(); m_dwState = RAS_CLIENT_STATE_NONE; //delete if any timers if( m_hRegTTLTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTTLTimer, NULL ); m_hRegTTLTimer = NULL; } if( m_hUnRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hUnRegTimer, NULL ); m_hUnRegTimer = NULL; m_dwUnRegRetryCount = 0; } if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL ); m_hRegTimer = NULL; } if( m_pRRQExpireContext != NULL ) { delete m_pRRQExpireContext; m_pRRQExpireContext = NULL; } if( m_pURQExpireContext != NULL ) { delete m_pURQExpireContext; m_pURQExpireContext = NULL; } m_RegisterState = RAS_REGISTER_STATE_IDLE; m_dwSendFreeLen = 0; m_dwRegRetryCount = 0; m_dwUnRegRetryCount = 0; m_dwCallsInProgress = 0; m_lastRegisterSeqNum = 0; m_wTTLSeqNumber = 0; m_UnRegisterSeqNum = 0; m_wRASSeqNum = 0; m_dwRegTimeToLive = 0; ZeroMemory( (PVOID)&m_GKAddress, sizeof(SOCKADDR_IN) ); ZeroMemory( (PVOID)&m_ASNCoderInfo, sizeof(ASN1_CODER_INFO) ); ZeroMemory( (PVOID)&m_PendingURQ, sizeof(PENDINGURQ) ); ZeroMemory( (PVOID)&m_RASEndpointID, sizeof(ENDPOINT_ID) ); break; default: _ASSERTE(FALSE); break; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "RAS Shutdown exited:%p.",this )); } BOOL RAS_CLIENT::FreeSendList( PLIST_ENTRY pListHead ) { PLIST_ENTRY pLE; RAS_SEND_CONTEXT * pSendContext; H323DBG(( DEBUG_LEVEL_ERROR, "FreeSendList entered." )); // process list until empty while( IsListEmpty(pListHead) == FALSE ) { // retrieve first entry pLE = RemoveHeadList(pListHead); // convert list entry to structure pointer pSendContext = CONTAINING_RECORD( pLE, RAS_SEND_CONTEXT, ListEntry ); // release memory if( pSendContext != NULL ) { delete pSendContext; pSendContext = NULL; } } H323DBG(( DEBUG_LEVEL_ERROR, "FreeSendList exited:%p.", this )); // success return TRUE; } //!!always called from a lock RAS_SEND_CONTEXT * RAS_CLIENT::AllocSendBuffer(void) { RAS_SEND_CONTEXT *pSendBuf; H323DBG(( DEBUG_LEVEL_TRACE, "AllocSendBuffer entered:%p.",this )); if( m_dwSendFreeLen ) { m_dwSendFreeLen--; _ASSERTE( IsListEmpty(&m_sendFreeList) == FALSE ); LIST_ENTRY *pLE = RemoveHeadList( &m_sendFreeList ); pSendBuf = CONTAINING_RECORD( pLE, RAS_SEND_CONTEXT, ListEntry ); } else { pSendBuf = (RAS_SEND_CONTEXT*)new RAS_SEND_CONTEXT; } H323DBG(( DEBUG_LEVEL_TRACE, "AllocSendBuffer exited:%p.",this )); return pSendBuf; } //!!always called from a lock void RAS_CLIENT::FreeSendBuffer( IN RAS_SEND_CONTEXT * pBuffer ) { H323DBG(( DEBUG_LEVEL_TRACE, "FreeSendBuffer entered:%p.",this )); if(m_dwSendFreeLen < RASIO_SEND_BUFFER_LIST_MAX ) { m_dwSendFreeLen++; InsertHeadList( &m_sendFreeList, &pBuffer->ListEntry ); } else { delete pBuffer; } H323DBG(( DEBUG_LEVEL_TRACE, "FreeSendBuffer exited:%p.",this )); } //RAS client functions void NTAPI RAS_CLIENT::RegExpiredCallback ( IN PVOID ContextParameter, // ExpContext IN BOOLEAN TimerFired) // not used { EXPIRE_CONTEXT * pExpireContext; RAS_CLIENT * This; H323DBG(( DEBUG_LEVEL_TRACE, "RegExpiredCallback - entered." )); _ASSERTE( ContextParameter ); pExpireContext = (EXPIRE_CONTEXT *)ContextParameter; _ASSERTE( m_pRRQExpireContext == pExpireContext ); _ASSERTE(pExpireContext -> RasClient); This = (RAS_CLIENT *) pExpireContext -> RasClient; This -> RegExpired (pExpireContext -> seqNumber); H323DBG(( DEBUG_LEVEL_TRACE, "RegExpiredCallback - exited." )); delete pExpireContext; } void NTAPI RAS_CLIENT::UnregExpiredCallback( IN PVOID ContextParameter, // ExpContext IN BOOLEAN TimerFired) // not used { EXPIRE_CONTEXT * pExpireContext; RAS_CLIENT * This; H323DBG(( DEBUG_LEVEL_TRACE, "UnregExpiredCallback - entered." )); _ASSERTE(ContextParameter); pExpireContext = (EXPIRE_CONTEXT *) ContextParameter; _ASSERTE( m_pURQExpireContext == pExpireContext ); _ASSERTE( pExpireContext -> RasClient ); This = (RAS_CLIENT *) pExpireContext -> RasClient; This -> UnregExpired( pExpireContext -> seqNumber ); H323DBG(( DEBUG_LEVEL_TRACE, "UnregExpiredCallback - exited." )); delete pExpireContext; } void NTAPI RAS_CLIENT::TTLExpiredCallback( IN PVOID ContextParameter, // ExpContext IN BOOLEAN TimerFired) // not used { RAS_CLIENT * This; _ASSERTE(ContextParameter); This = (RAS_CLIENT*)ContextParameter; _ASSERTE(This == &g_RasClient); This -> TTLExpired(); } //If we have already sent RRQ to this GK then this RRQ is supposed to rplace //the original alias list with the new list BOOL RAS_CLIENT::SendRRQ( IN long seqNumber, IN PALIASCHANGE_REQUEST pAliasChangeRequest ) { RasMessage rasMessage; RegistrationRequest * RRQ; SOCKADDR_IN sockAddr; EXPIRE_CONTEXT * pExpireContext = NULL; RegistrationRequest_callSignalAddress CallSignalAddressSequence; RegistrationRequest_rasAddress RasAddressSequence; H323DBG(( DEBUG_LEVEL_TRACE, "SendRRQ entered:%p.",this )); pExpireContext = new EXPIRE_CONTEXT; if( pExpireContext == NULL ) { return FALSE; } Lock(); // initialize the structure ZeroMemory (&rasMessage, sizeof rasMessage); rasMessage.choice = registrationRequest_chosen; RRQ = &rasMessage.u.registrationRequest; RRQ -> bit_mask = 0; RRQ -> protocolIdentifier = OID_H225ProtocolIdentifierV2; // get sequence number if( seqNumber != NOT_RESEND_SEQ_NUM ) { RRQ -> requestSeqNum = (WORD)seqNumber; } else { RRQ -> requestSeqNum = GetNextSeqNum(); if( pAliasChangeRequest == NULL ) { m_lastRegisterSeqNum = RRQ -> requestSeqNum; } else { pAliasChangeRequest->wRequestSeqNum = RRQ -> requestSeqNum; } } H323DBG(( DEBUG_LEVEL_TRACE, "RRQ seqNum:%d.", RRQ -> requestSeqNum )); sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(LOWORD(g_RegistrySettings.dwQ931ListenPort)); //we are listening for Q931 conns on all local interfaces //so specify just one of the local IP addresses sockAddr.sin_addr.s_addr = m_sockAddr.sin_addr.s_addr; SetTransportAddress( &sockAddr, &CallSignalAddressSequence.value); CallSignalAddressSequence.next = NULL; RRQ -> callSignalAddress = &CallSignalAddressSequence; // ras address. The UDP socket for this GK RasAddressSequence.next = NULL; RasAddressSequence.value = m_transportAddress; RRQ -> rasAddress = &RasAddressSequence; // fill in endpoint type RRQ -> terminalType.bit_mask |= terminal_present; RRQ -> terminalType.terminal.bit_mask = 0; //fill in terminal alias list if( pAliasChangeRequest && pAliasChangeRequest->pAliasList ) { RRQ -> terminalAlias = (RegistrationRequest_terminalAlias *) SetMsgAddressAlias( pAliasChangeRequest->pAliasList ); if (NULL == RRQ -> terminalAlias) { goto cleanup; } RRQ -> bit_mask |= RegistrationRequest_terminalAlias_present; RRQ -> bit_mask |= RegistrationRequest_endpointIdentifier_present; RRQ->endpointIdentifier.length = pAliasChangeRequest->rasEndpointID.length; RRQ->endpointIdentifier.value = pAliasChangeRequest->rasEndpointID.value; } else if( m_pAliasList && m_pAliasList->wCount ) { RRQ -> terminalAlias = (RegistrationRequest_terminalAlias *) SetMsgAddressAlias( m_pAliasList ); if (NULL == RRQ -> terminalAlias) { goto cleanup; } RRQ -> bit_mask |= RegistrationRequest_terminalAlias_present; } else { _ASSERTE(0); } //endpointVendor CopyVendorInfo( &(RRQ -> endpointVendor) ); //a few random booleans RRQ -> discoveryComplete = FALSE; RRQ -> keepAlive = FALSE; RRQ -> willSupplyUUIEs = FALSE; // encode and send if( !IssueSend(&rasMessage) ) { goto cleanup; } //delete if any previous TTL timer if( m_hRegTTLTimer ) { DeleteTimerQueueTimer(H323TimerQueue, m_hRegTTLTimer, NULL ); m_hRegTTLTimer = NULL; } //delete if any previous RRQ sent timer if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL ); m_hRegTimer = NULL; } pExpireContext -> RasClient = this; pExpireContext -> seqNumber = RRQ -> requestSeqNum; if( !CreateTimerQueueTimer( &m_hRegTimer, H323TimerQueue, RAS_CLIENT::RegExpiredCallback, pExpireContext, REG_EXPIRE_TIME, 0, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ) ) { goto cleanup; } if( RRQ -> bit_mask & RegistrationRequest_terminalAlias_present ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) RRQ -> terminalAlias); } m_dwRegRetryCount++; if( pAliasChangeRequest == NULL ) { m_RegisterState = RAS_REGISTER_STATE_RRQSENT; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "SendRRQ exited:%p.", this )); return TRUE; cleanup: if( RRQ -> bit_mask & RegistrationRequest_terminalAlias_present ) { FreeAddressAliases( (PSetup_UUIE_destinationAddress) RRQ -> terminalAlias); } if( pExpireContext != NULL ) { delete pExpireContext; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "SendRRQ error:%p.",this )); return FALSE; } BOOL RAS_CLIENT::SendURQ( IN long seqNumber, IN EndpointIdentifier * pEndpointID ) { RasMessage rasMessage; UnregistrationRequest * URQ; SOCKADDR_IN sockAddr; EXPIRE_CONTEXT * pExpireContext = NULL; UnregistrationRequest_callSignalAddress CallSignalAddressSequence; H323DBG(( DEBUG_LEVEL_TRACE, "SendURQ entered:%p.",this )); Lock(); if( m_RegisterState == RAS_REGISTER_STATE_RRQSENT ) { //store the seqNumber of this RRQ and send URQ if we recv RCF m_PendingURQ.RRQSeqNumber = m_lastRegisterSeqNum; Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "rrq sent:so pending urq." )); return TRUE; } else if( m_RegisterState != RAS_REGISTER_STATE_REGISTERED ) { //if already unregistered or URQ sent then return success Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "current state:%d.", m_RegisterState )); return TRUE; } pExpireContext = new EXPIRE_CONTEXT; if( pExpireContext == NULL ) { goto cleanup; } ZeroMemory (&rasMessage, sizeof RasMessage); rasMessage.choice = unregistrationRequest_chosen; URQ = &rasMessage.u.unregistrationRequest; // get sequence number if( seqNumber != NOT_RESEND_SEQ_NUM ) { URQ -> requestSeqNum = (WORD)seqNumber; } else { m_UnRegisterSeqNum = GetNextSeqNum(); URQ -> requestSeqNum = (WORD)m_UnRegisterSeqNum; } H323DBG(( DEBUG_LEVEL_TRACE, "RRQ seqNum:%d.", URQ -> requestSeqNum )); sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(LOWORD(g_RegistrySettings.dwQ931ListenPort)); //we are listening for Q931 conns on all local interfaces //so specify just one of the local IP addresses sockAddr.sin_addr.s_addr = m_sockAddr.sin_addr.s_addr; SetTransportAddress( &sockAddr, &CallSignalAddressSequence.value); CallSignalAddressSequence.next = NULL; URQ -> callSignalAddress = &CallSignalAddressSequence; //get endpointidentifier by using GetComputerNameW URQ -> bit_mask |= UnregistrationRequest_endpointIdentifier_present; if( pEndpointID != NULL ) { URQ->endpointIdentifier.length = pEndpointID ->length; URQ->endpointIdentifier.value = pEndpointID -> value; } else { URQ->endpointIdentifier.length = m_RASEndpointID.length; URQ->endpointIdentifier.value = m_RASEndpointID.value; } // encode and send if( !IssueSend( &rasMessage ) ) { goto cleanup; } pExpireContext -> RasClient = this; pExpireContext -> seqNumber = URQ -> requestSeqNum; //delete if any previous RRQ sent timer if( m_hUnRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hUnRegTimer, NULL ); m_hUnRegTimer = NULL; m_dwUnRegRetryCount = 0; } if( !CreateTimerQueueTimer( &m_hUnRegTimer, H323TimerQueue, RAS_CLIENT::UnregExpiredCallback, pExpireContext, REG_EXPIRE_TIME, 0, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE) ) { goto cleanup; } //delete if any TTL timer if( m_hRegTTLTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTTLTimer, NULL ); m_hRegTTLTimer = NULL; } m_dwUnRegRetryCount++; m_RegisterState = RAS_REGISTER_STATE_URQSENT; Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "SendURQ exited:%p.",this )); return TRUE; cleanup: if( pExpireContext != NULL ) { delete pExpireContext; } Unlock(); return FALSE; } //!!always called from a lock BOOL RAS_CLIENT::SendUCF( IN WORD seqNumber ) { RasMessage rasMessage; UnregistrationConfirm * UCF; H323DBG(( DEBUG_LEVEL_TRACE, "SendUCF entered:%p.",this )); // initialize the structure ZeroMemory (&rasMessage, sizeof rasMessage); rasMessage.choice = unregistrationConfirm_chosen; UCF = &rasMessage.u.unregistrationConfirm; UCF -> bit_mask = 0; UCF -> requestSeqNum = seqNumber; if( !IssueSend( &rasMessage ) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "SendUCF exited:%p.",this )); return TRUE; } //!!always called from a lock BOOL RAS_CLIENT::SendURJ( IN WORD seqNumber, IN DWORD dwReason ) { RasMessage rasMessage; UnregistrationReject * URJ; H323DBG(( DEBUG_LEVEL_TRACE, "SendURJ entered:%p.",this )); // initialize the structure ZeroMemory (&rasMessage, sizeof rasMessage); rasMessage.choice = unregistrationReject_chosen; URJ = &rasMessage.u.unregistrationReject; URJ -> bit_mask = 0; URJ -> requestSeqNum = seqNumber; URJ -> rejectReason.choice = (WORD)dwReason; if( !IssueSend( &rasMessage ) ) { return FALSE; } H323DBG(( DEBUG_LEVEL_TRACE, "SendURJ exited:%p.",this )); return TRUE; } //!!always called from a lock void RAS_CLIENT::ProcessRasMessage( IN RasMessage *pRasMessage ) { PH323_CALL pCall = NULL; ASN1decoding_s ASN1decInfo; H323DBG(( DEBUG_LEVEL_TRACE, "RAS: processing RasMessage" )); //Verify that the RCF came from the expected gatekeeper switch( pRasMessage -> choice ) { case registrationReject_chosen: OnRegistrationReject( &pRasMessage -> u.registrationReject ); break; case registrationConfirm_chosen: OnRegistrationConfirm( &pRasMessage -> u.registrationConfirm ); break; case unregistrationRequest_chosen: OnUnregistrationRequest( &pRasMessage -> u.unregistrationRequest ); break; case unregistrationReject_chosen: OnUnregistrationReject( &pRasMessage -> u.unregistrationReject ); break; case unregistrationConfirm_chosen: OnUnregistrationConfirm( &pRasMessage -> u.unregistrationConfirm ); break; case infoRequest_chosen: CopyMemory( (PVOID)&ASN1decInfo, (PVOID)m_ASNCoderInfo.pDecInfo, sizeof(ASN1decoding_s) ); //This function should be always called in //a lock and it unlocks the the ras client OnInfoRequest( &pRasMessage -> u.infoRequest ); ASN1_FreeDecoded( &ASN1decInfo, pRasMessage, RasMessage_PDU ); //return here since we have already unlocked and freed the buffer return; default: CopyMemory( (PVOID)&ASN1decInfo, (PVOID)m_ASNCoderInfo.pDecInfo, sizeof(ASN1decoding_s) ); //Don't loclk the RAS client while locking the call object. Unlock(); HandleRASCallMessage( pRasMessage ); ASN1_FreeDecoded( &ASN1decInfo, pRasMessage, RasMessage_PDU ); //return here since we have already unlocked and freed the buffer return; } ASN1_FreeDecoded( m_ASNCoderInfo.pDecInfo, pRasMessage, RasMessage_PDU ); Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "ProcessRasMessage exited:%p.",this )); } //!!always called from a lock void HandleRASCallMessage( IN RasMessage *pRasMessage ) { PH323_CALL pCall = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "RAS: processing RASCallMessage" )); switch( pRasMessage -> choice ) { case admissionConfirm_chosen: pCall = g_pH323Line -> FindCallByARQSeqNumAndLock( pRasMessage -> u.admissionConfirm.requestSeqNum); if( pCall != NULL ) { pCall -> OnAdmissionConfirm( &pRasMessage->u.admissionConfirm ); pCall -> Unlock(); } else H323DBG(( DEBUG_LEVEL_ERROR, "acf:call not found:%d.", pRasMessage -> u.admissionConfirm.requestSeqNum )); break; case admissionReject_chosen: pCall = g_pH323Line -> FindCallByARQSeqNumAndLock( pRasMessage -> u.admissionReject.requestSeqNum ); if( pCall != NULL ) { pCall -> OnAdmissionReject( &pRasMessage->u.admissionReject ); pCall -> Unlock(); } else H323DBG(( DEBUG_LEVEL_ERROR, "arj:call not found:%d.", pRasMessage -> u.admissionReject.requestSeqNum )); break; case disengageRequest_chosen: pCall = g_pH323Line -> FindCallByCallRefAndLock( pRasMessage -> u.disengageRequest.callReferenceValue ); if( pCall != NULL ) { pCall -> OnDisengageRequest( &pRasMessage -> u.disengageRequest ); pCall -> Unlock(); } else H323DBG(( DEBUG_LEVEL_ERROR, "drq:call not found:%d.", pRasMessage -> u.disengageRequest.callReferenceValue )); break; case disengageConfirm_chosen: pCall = g_pH323Line -> FindCallByDRQSeqNumAndLock( pRasMessage -> u.disengageConfirm.requestSeqNum ); if( pCall != NULL ) { pCall -> OnDisengageConfirm( &pRasMessage -> u.disengageConfirm ); pCall -> Unlock(); } else H323DBG(( DEBUG_LEVEL_ERROR, "dcf:call not found:%d.", pRasMessage -> u.disengageConfirm.requestSeqNum )); break; case disengageReject_chosen: pCall = g_pH323Line -> FindCallByDRQSeqNumAndLock( pRasMessage -> u.disengageReject.requestSeqNum ); if( pCall != NULL ) { pCall -> OnDisengageReject( &pRasMessage -> u.disengageReject ); pCall -> Unlock(); } else H323DBG(( DEBUG_LEVEL_ERROR, "drj:call not found:%d.", pRasMessage -> u.disengageReject.requestSeqNum)); break; case requestInProgress_chosen: pCall = g_pH323Line -> FindCallByARQSeqNumAndLock( pRasMessage->u.requestInProgress.requestSeqNum ); if( pCall != NULL ) { pCall -> OnRequestInProgress( &pRasMessage->u.requestInProgress ); pCall -> Unlock(); } else H323DBG(( DEBUG_LEVEL_ERROR, "rip:call not found:%d.", pRasMessage->u.requestInProgress.requestSeqNum )); break; default: _ASSERTE(0); H323DBG(( DEBUG_LEVEL_ERROR, "ProcessRASMessage: wrong message:%d", pRasMessage -> choice)); break; } H323DBG(( DEBUG_LEVEL_TRACE, "HandleRASCallMessage exited" )); } void RAS_CLIENT::RegExpired( IN WORD seqNumber ) { H323DBG(( DEBUG_LEVEL_TRACE, "RegExpired entered:%p.", this )); Lock(); m_pRRQExpireContext = NULL; if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL ); m_hRegTimer = NULL; } /* 1. Registered:ignore this timeout 2. RRQ sent: (the endpoint has initiated the process of registering but hasn't heard from the GK yet) Resend the RRQ 3. Unregistered: ignore this imeout 4. URQ sent: (the endpoint has initiated the process of unregistering but hasn't heard from the GK yet) ignore this timeout 5. Idle: The GK client object has just been initialized and hasn't done anything. This should not happen. */ switch( m_RegisterState ) { case RAS_REGISTER_STATE_RRQSENT: if( m_dwRegRetryCount < REG_RETRY_MAX ) { if( !SendRRQ( (long)seqNumber, NULL ) ) { m_RegisterState = RAS_REGISTER_STATE_RRQEXPIRED; } } else { m_RegisterState = RAS_REGISTER_STATE_RRQEXPIRED; } break; case RAS_REGISTER_STATE_REGISTERED: case RAS_REGISTER_STATE_URQSENT: case RAS_REGISTER_STATE_UNREGISTERED: break; case RAS_REGISTER_STATE_IDLE: _ASSERTE(0); break; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "RegExpired exited:%p.",this )); } void RAS_CLIENT::TTLExpired() { RasMessage rasMessage; RegistrationRequest * RRQ; H323DBG(( DEBUG_LEVEL_TRACE, "TTLExpired entered:%p.",this )); Lock(); if( m_RegisterState == RAS_REGISTER_STATE_REGISTERED ) { //send light weight RRQ // initialize the structure ZeroMemory (&rasMessage, sizeof rasMessage); rasMessage.choice = registrationRequest_chosen; RRQ = &rasMessage.u.registrationRequest; RRQ -> bit_mask = 0; RRQ -> protocolIdentifier = OID_H225ProtocolIdentifierV2; RRQ -> bit_mask |= keepAlive_present; RRQ -> keepAlive = TRUE; //copy TTL RRQ -> bit_mask |= RegistrationRequest_timeToLive_present; RRQ -> timeToLive = m_dwRegTimeToLive; //endpoint identifier RRQ -> bit_mask |= RegistrationRequest_endpointIdentifier_present; RRQ->endpointIdentifier.length = m_RASEndpointID.length; RRQ->endpointIdentifier.value = m_RASEndpointID.value; //seqNumber m_wTTLSeqNumber = GetNextSeqNum(); RRQ -> requestSeqNum = (WORD)m_wTTLSeqNumber; //what about gatekeeperIdentifier, tokens? // encode and send if( !IssueSend(&rasMessage) ) { H323DBG(( DEBUG_LEVEL_TRACE, "SendLwtRRQ error:%p.",this )); Unlock(); return; } } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "TTLExpired exited:%p.",this )); } void RAS_CLIENT::UnregExpired( IN WORD seqNumber ) { H323DBG(( DEBUG_LEVEL_TRACE, "UnregExpired entered:%p.",this )); Lock(); m_pURQExpireContext = NULL; if( m_hUnRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hUnRegTimer, NULL); m_hUnRegTimer = NULL; m_dwUnRegRetryCount = 0; } switch( m_RegisterState ) { case RAS_REGISTER_STATE_URQSENT: if( m_dwUnRegRetryCount < URQ_RETRY_MAX ) { SendURQ( (long)seqNumber, NULL ); } else { m_RegisterState = RAS_REGISTER_STATE_URQEXPIRED; } break; case RAS_REGISTER_STATE_REGISTERED: case RAS_REGISTER_STATE_RRQSENT: case RAS_REGISTER_STATE_UNREGISTERED: break; case RAS_REGISTER_STATE_IDLE: _ASSERTE(0); break; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "UnregExpired exited:%p.",this )); } void RAS_CLIENT::OnUnregistrationRequest( IN UnregistrationRequest *URQ ) { H323DBG(( DEBUG_LEVEL_TRACE, "OnUnregistrationRequest entered:%p.", this )); _ASSERTE( m_RegisterState != RAS_REGISTER_STATE_IDLE ); if( (m_RegisterState == RAS_REGISTER_STATE_UNREGISTERED) || (m_RegisterState == RAS_REGISTER_STATE_RRJ) ) { SendURJ( URQ -> requestSeqNum, notCurrentlyRegistered_chosen ); } else if( m_dwCallsInProgress ) { SendURJ( URQ -> requestSeqNum, callInProgress_chosen ); } else { m_RegisterState = RAS_REGISTER_STATE_UNREGISTERED; SendUCF( URQ -> requestSeqNum ); //try to register again if( !SendRRQ( NOT_RESEND_SEQ_NUM, NULL ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "couldn't send rrq on urq request." )); } } H323DBG(( DEBUG_LEVEL_TRACE, "OnUnregistrationRequest exited:%p.",this )); } //!!always called from a lock void RAS_CLIENT::OnUnregistrationConfirm( IN UnregistrationConfirm *UCF ) { H323DBG((DEBUG_LEVEL_TRACE, "OnUnregistrationConfirm entered:%p.",this)); if( UCF -> requestSeqNum != m_UnRegisterSeqNum ) return; _ASSERTE( m_hUnRegTimer ); if( m_hUnRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hUnRegTimer, NULL); m_hUnRegTimer = NULL; m_dwUnRegRetryCount = 0; } if( (m_RegisterState == RAS_REGISTER_STATE_URQSENT) || (m_RegisterState == RAS_REGISTER_STATE_URQEXPIRED) ) { //delete if any TTL timer if( m_hRegTTLTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTTLTimer, NULL ); m_hRegTTLTimer = NULL; } m_RegisterState = RAS_REGISTER_STATE_UNREGISTERED; } H323DBG(( DEBUG_LEVEL_TRACE, "OnUnregistrationConfirm exited:%p.",this)); } //!!always called from a lock void RAS_CLIENT::OnUnregistrationReject( IN UnregistrationReject *URJ ) { H323DBG(( DEBUG_LEVEL_TRACE, "OnUnregistrationReject entered:%p.",this )); if( URJ -> requestSeqNum != m_UnRegisterSeqNum ) { return; } if( m_hUnRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hUnRegTimer, NULL); m_hUnRegTimer = NULL; m_dwUnRegRetryCount = 0; } if( (m_RegisterState == RAS_REGISTER_STATE_URQSENT) || (m_RegisterState == RAS_REGISTER_STATE_URQEXPIRED) ) { m_RegisterState = RAS_REGISTER_STATE_UNREGISTERED; } H323DBG(( DEBUG_LEVEL_TRACE, "OnUnregistrationReject exited:%p.",this )); } //!!always called from a lock void RAS_CLIENT::OnRegistrationReject( IN RegistrationReject * RRJ ) { H323DBG(( DEBUG_LEVEL_TRACE, "OnRegistrationReject entered:%p.",this )); if( RRJ -> requestSeqNum == m_wTTLSeqNumber ) { //Keep alive failed. So start registration process again. //This will change the RAS registration state to RRQSENT from REGISTERED. if( !SendRRQ( NOT_RESEND_SEQ_NUM, NULL ) ) { H323DBG(( DEBUG_LEVEL_ERROR, "couldn't send rrq on Keep alive failure." )); m_RegisterState = RAS_REGISTER_STATE_UNREGISTERED; } } else if( RRJ -> requestSeqNum == m_lastRegisterSeqNum ) { if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL); m_hRegTimer = NULL; m_dwRegRetryCount = 0; } if( (m_RegisterState == RAS_REGISTER_STATE_RRQSENT) || (m_RegisterState == RAS_REGISTER_STATE_RRQEXPIRED) ) { m_RegisterState = RAS_REGISTER_STATE_RRJ; } } H323DBG(( DEBUG_LEVEL_TRACE, "OnRegistrationReject exitd:%p.",this )); } //!!always called in lock void RAS_CLIENT::OnRegistrationConfirm( IN RegistrationConfirm * RCF ) { LIST_ENTRY *pListEntry = NULL; PALIASCHANGE_REQUEST pAliasChangeRequest = NULL; H323DBG(( DEBUG_LEVEL_TRACE, "OnRegistrationConfirm entered:%p.", this )); if( RCF -> requestSeqNum == m_PendingURQ.RRQSeqNumber ) { //The timer could have been startd with the last RRQ, //irrespective of the current state of registration. if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL); m_hRegTimer = NULL; m_dwRegRetryCount = 0; } //send URQ with the endpointIdentifier SendURQ( NOT_RESEND_SEQ_NUM, &RCF->endpointIdentifier ); H323DBG(( DEBUG_LEVEL_TRACE, "sending pending URQ for RRQ:%d", RCF->requestSeqNum )); return; } else if( RCF -> requestSeqNum == m_lastRegisterSeqNum ) { //The timer could have been startd with the last RRQ, //irrespective of the current state of registration. if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL); m_hRegTimer = NULL; m_dwRegRetryCount = 0; } switch (m_RegisterState) { case RAS_REGISTER_STATE_REGISTERED: if (RCF->requestSeqNum == m_wTTLSeqNumber) { H323DBG(( DEBUG_LEVEL_TRACE, "RCF for TTL-RRQ." )); } else { H323DBG(( DEBUG_LEVEL_WARNING, "warning: received RCF, but was already registered-ignoring")); } break; case RAS_REGISTER_STATE_RRQEXPIRED: H323DBG(( DEBUG_LEVEL_TRACE, "received RCF, but registration already expired, send URQ" )); SendURQ (NOT_RESEND_SEQ_NUM, &RCF->endpointIdentifier); break; case RAS_REGISTER_STATE_RRQSENT: //expecting RRQ. gatekeeper has responded. m_RegisterState = RAS_REGISTER_STATE_REGISTERED; CopyMemory( (PVOID)m_RASEndpointID.value, (PVOID)RCF -> endpointIdentifier.value, RCF -> endpointIdentifier.length * sizeof(WCHAR) ); m_RASEndpointID.value[RCF -> endpointIdentifier.length] = L'\0'; m_RASEndpointID.length = (WORD)RCF -> endpointIdentifier.length; InitializeTTLTimer( RCF ); break; default: H323DBG(( DEBUG_LEVEL_TRACE, "RAS: received RRQ, but was in unexpected state")); break; } } else if( RCF -> requestSeqNum == m_wTTLSeqNumber ) { //The timer could have been startd with the last RRQ, //irrespective of the current state of registration. if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL); m_hRegTimer = NULL; m_dwRegRetryCount = 0; } //look for the change in keepalive interval. InitializeTTLTimer( RCF ); } else { //Try to find if this is a alias change request. for( pListEntry = m_aliasChangeRequestList.Flink; pListEntry != &m_aliasChangeRequestList; pListEntry = pListEntry -> Flink ) { pAliasChangeRequest = CONTAINING_RECORD( pListEntry, ALIASCHANGE_REQUEST, listEntry ); if( pAliasChangeRequest -> wRequestSeqNum == RCF -> requestSeqNum ) { break; } } if( pListEntry != &m_aliasChangeRequestList ) { //The timer could have been startd with the last RRQ, //irrespective of the current state of registration. if( m_hRegTimer != NULL ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTimer, NULL); m_hRegTimer = NULL; m_dwRegRetryCount = 0; } //if registration has changed since this request was made then //ignore the message. if( memcmp( (PVOID)pAliasChangeRequest -> rasEndpointID.value, m_RASEndpointID.value, m_RASEndpointID.length * sizeof(WCHAR) ) == 0 ) { //update the alias list. FreeAliasNames( m_pAliasList ); m_pAliasList = pAliasChangeRequest->pAliasList; RemoveEntryList( &pAliasChangeRequest->listEntry ); delete pAliasChangeRequest; } } } H323DBG(( DEBUG_LEVEL_TRACE, "OnRegistrationConfirm exited:%p.", this )); } //!!always called in a lock. BOOL RAS_CLIENT::InitializeTTLTimer( IN RegistrationConfirm * RCF ) { H323DBG(( DEBUG_LEVEL_TRACE, "InitializeTTLTimer - entered." )); if( (RCF->bit_mask & RegistrationConfirm_timeToLive_present) && ( (m_dwRegTimeToLive != RCF->timeToLive) || (m_hRegTTLTimer == NULL) ) ) { m_dwRegTimeToLive = RCF->timeToLive; H323DBG(( DEBUG_LEVEL_TRACE, "timetolive value:%d.", m_dwRegTimeToLive )); //delete if any previous TTL timer if( m_hRegTTLTimer ) { DeleteTimerQueueTimer( H323TimerQueue, m_hRegTTLTimer, NULL ); m_hRegTTLTimer = NULL; } //start a timer to send lightweight RRQ afetr given time if( !CreateTimerQueueTimer( &m_hRegTTLTimer, H323TimerQueue, RAS_CLIENT::TTLExpiredCallback, this, (m_dwRegTimeToLive - REG_TTL_MARGIN)*1000, (m_dwRegTimeToLive - REG_TTL_MARGIN)*1000, WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ) ) { H323DBG ((DEBUG_LEVEL_ERROR, "failed to create timer queue timer")); m_hRegTTLTimer = NULL; return FALSE; } } H323DBG(( DEBUG_LEVEL_TRACE, "InitializeTTLTimer - exited." )); return TRUE; } void RAS_CLIENT::OnInfoRequest ( IN InfoRequest * IRQ) { PH323_CALL pCall; SOCKADDR_IN ReplyAddress; InfoRequestResponse_perCallInfo CallInfoList; InfoRequestResponse_perCallInfo * pCallInfoList = NULL; InfoRequestResponse_perCallInfo_Seq * CallInfo; HRESULT hr; int iIndex, jIndex; int iNumCalls = 0; int iCallTableSize; H323DBG(( DEBUG_LEVEL_TRACE, "OnInfoRequest - entered." )); if (m_RegisterState != RAS_REGISTER_STATE_REGISTERED) { H323DBG ((DEBUG_LEVEL_ERROR, "RAS: received InfoRequest, but was not registered")); Unlock(); return; } if (IRQ->bit_mask & replyAddress_present) { if (!GetTransportAddress (&IRQ -> replyAddress, &ReplyAddress)) { H323DBG ((DEBUG_LEVEL_ERROR, "RAS: received InfoRequest, but replyAddress was malformed")); Unlock(); return; } } else { ReplyAddress = m_GKAddress; } //Don't loclk the RAS client while locking the call object. Unlock(); if( IRQ -> callReferenceValue ) { //query is for a specific call. So find the call and then send IRR pCall = g_pH323Line -> FindCallByCallRefAndLock( IRQ -> callReferenceValue ); if( pCall ) { CallInfo = &CallInfoList.value; CallInfoList.next = NULL; ZeroMemory (CallInfo, sizeof (InfoRequestResponse_perCallInfo_Seq)); CallInfo -> callIdentifier.guid.length = sizeof (GUID); CallInfo -> conferenceID.length = sizeof (GUID); hr = pCall -> GetCallInfo ( (GUID *) &CallInfo -> callIdentifier.guid.value, (GUID *) &CallInfo -> conferenceID.value); if( hr != S_OK ) { H323DBG ((DEBUG_LEVEL_ERROR, "RAS: call is disconnected for crv (%04XH).", IRQ -> callReferenceValue)); return; } pCall -> Unlock(); CallInfo -> callReferenceValue = IRQ -> callReferenceValue; CallInfo -> callType.choice = pointToPoint_chosen; CallInfo -> callModel.choice = direct_chosen; } else { H323DBG(( DEBUG_LEVEL_ERROR, "RAS: received InfoRequest for nonexistent crv (%04XH).", IRQ -> callReferenceValue)); return; } SendInfoRequestResponse (&ReplyAddress, IRQ -> requestSeqNum, &CallInfoList); } else { //send the info about all the active calls. iNumCalls = g_pH323Line->GetNoOfCalls(); if( iNumCalls != 0 ) { pCallInfoList = new InfoRequestResponse_perCallInfo[iNumCalls]; } if( pCallInfoList != NULL ) { //lock the call table g_pH323Line -> LockCallTable(); iCallTableSize = g_pH323Line->GetCallTableSize(); //lock the call so that nobody else would be able to delete the call for( jIndex=0, iIndex=0; (iIndex < iCallTableSize) && (jIndex < iNumCalls); iIndex++ ) { pCall = g_pH323Line->GetCallAtIndex(iIndex); if( pCall != NULL ) { pCall -> Lock(); CallInfo = &(pCallInfoList[jIndex++].value); ZeroMemory( CallInfo, sizeof (InfoRequestResponse_perCallInfo_Seq) ); CallInfo -> callIdentifier.guid.length = sizeof( GUID ); CallInfo -> conferenceID.length = sizeof( GUID ); pCall -> GetCallInfo( (GUID *) &CallInfo -> callIdentifier.guid.value, (GUID *) &CallInfo -> conferenceID.value); CallInfo -> callReferenceValue = pCall->GetCallRef(); pCall -> Unlock(); CallInfo -> callType.choice = pointToPoint_chosen; CallInfo -> callModel.choice = direct_chosen; } } for( iIndex=0; iIndex < jIndex-1; iIndex++ ) { pCallInfoList[iIndex].next = &(pCallInfoList[iIndex+1]); } pCallInfoList[iIndex].next = NULL; //unlock the call table g_pH323Line -> UnlockCallTable(); } SendInfoRequestResponse( &ReplyAddress, IRQ -> requestSeqNum, pCallInfoList ); if( pCallInfoList != NULL ) { delete pCallInfoList; } } H323DBG(( DEBUG_LEVEL_TRACE, "OnInfoRequest - exited." )); } HRESULT RAS_CLIENT::SendInfoRequestResponse ( IN SOCKADDR_IN * RasAddress, IN USHORT SequenceNumber, IN InfoRequestResponse_perCallInfo * CallInfoList) { RasMessage RasMessage; InfoRequestResponse * IRR; SOCKADDR_IN SocketAddress; HRESULT hr; H323DBG(( DEBUG_LEVEL_TRACE, "SendInfoRequestResponse - entered." )); Lock(); if( m_RegisterState == RAS_REGISTER_STATE_REGISTERED ) { InfoRequestResponse_callSignalAddress CallSignalAddressSequence; H323DBG(( DEBUG_LEVEL_TRACE, "SendIRR entered:%p.",this )); ZeroMemory (&RasMessage, sizeof RasMessage); RasMessage.choice = infoRequestResponse_chosen; IRR = &RasMessage.u.infoRequestResponse; IRR -> requestSeqNum = SequenceNumber; // we are listening for Q931 conns on all local interfaces // so specify just one of the local IP addresses // -XXX- fix for multihomed support later SocketAddress.sin_family = AF_INET; SocketAddress.sin_port = htons (LOWORD(g_RegistrySettings.dwQ931ListenPort)); SocketAddress.sin_addr.s_addr = m_sockAddr.sin_addr.s_addr; // callSignalAddress SetTransportAddress (&SocketAddress, &CallSignalAddressSequence.value); CallSignalAddressSequence.next = NULL; IRR -> callSignalAddress = &CallSignalAddressSequence; // rasAddress IRR -> rasAddress = m_transportAddress; // endpointIdentifier IRR -> endpointIdentifier.length = m_RASEndpointID.length; IRR -> endpointIdentifier.value = m_RASEndpointID.value; // fill in endpoint type IRR -> endpointType.bit_mask |= terminal_present; IRR -> endpointType.terminal.bit_mask = 0; if( CallInfoList ) { IRR -> bit_mask |= perCallInfo_present; IRR -> perCallInfo = CallInfoList; } // send the pdu hr = EncodeSendMessage (&RasMessage); } else { hr = E_FAIL; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "SendInfoRequestResponse - exited." )); return TRUE; } //!!always called from a lock BOOL RAS_CLIENT::InitializeIo (void) { DWORD dwFlags = 0; int AddressLength; H323DBG(( DEBUG_LEVEL_TRACE, "InitializeIo entered:%p.",this )); m_Socket = WSASocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); if( m_Socket == INVALID_SOCKET ) { WSAGetLastError(); return FALSE; } if( !H323BindIoCompletionCallback ( (HANDLE)m_Socket, RAS_CLIENT::IoCompletionCallback, 0)) { GetLastError(); goto cleanup; } m_sockAddr.sin_family = AF_INET; m_sockAddr.sin_port = htons (0); m_sockAddr.sin_addr.s_addr = GetLocalIPAddress( m_GKAddress.sin_addr.S_un.S_addr ); H323DBG(( DEBUG_LEVEL_TRACE, "gk sock addr:%lx.", m_sockAddr.sin_addr.s_addr )); if( bind( m_Socket, (SOCKADDR *)&m_sockAddr, sizeof(m_sockAddr) ) == SOCKET_ERROR ) { H323DBG(( DEBUG_LEVEL_ERROR, "Couldn't bind the RAS socket:%d, %p", WSAGetLastError(), this )); goto cleanup; } // now that we've bound to a dynamic UDP port, // query that port from the stack and store it. AddressLength = sizeof m_sockAddr; if( getsockname(m_Socket, (SOCKADDR *)&m_sockAddr, &AddressLength) == SOCKET_ERROR ) { H323DBG(( DEBUG_LEVEL_ERROR, "getsockname failed :%d, %p", WSAGetLastError(), this )); goto cleanup; } _ASSERTE( ntohs(m_sockAddr.sin_port) ); // fill in the IoTransportAddress structure. // this structure is the ASN.1-friendly transport // address of this client's endpoint. SetTransportAddress( &m_sockAddr, &m_transportAddress ); // initiate i/o ZeroMemory( (PVOID)&m_recvOverlapped, sizeof(RAS_RECV_CONTEXT) ); if( !IssueRecv() ) { goto cleanup; } H323DBG(( DEBUG_LEVEL_TRACE, "InitializeIo exited:%p.",this )); return TRUE; cleanup: closesocket(m_Socket); m_Socket = INVALID_SOCKET; return FALSE; } DWORD GetLocalIPAddress( IN DWORD dwRemoteAddr ) { DWORD dwLocalAddr = INADDR_ANY; SOCKADDR_IN sRemoteAddr; SOCKADDR_IN sLocalAddr; DWORD dwNumBytesReturned = 0; SOCKET querySocket; H323DBG(( DEBUG_LEVEL_TRACE, "GetLocalIPAddress - entered." )); ZeroMemory( (PVOID)&sRemoteAddr, sizeof(SOCKADDR_IN) ); ZeroMemory( (PVOID)&sLocalAddr, sizeof(SOCKADDR_IN) ); sRemoteAddr.sin_family = AF_INET; sRemoteAddr.sin_addr = *(struct in_addr *) &dwRemoteAddr; querySocket = WSASocket( AF_INET, // int af SOCK_DGRAM, // int type IPPROTO_UDP, // int protocol NULL, // LPWSAPROTOCOL_INFO lpProtocolInfo 0, // GROUP g WSA_FLAG_OVERLAPPED // DWORD dwFlags ); if( querySocket == INVALID_SOCKET ) { H323DBG(( DEBUG_LEVEL_ERROR, "getlocalIP wsasocket:%d.", WSAGetLastError() )); return dwLocalAddr; } if( WSAIoctl( querySocket, // SOCKET s SIO_ROUTING_INTERFACE_QUERY, // DWORD dwIoControlCode &sRemoteAddr, // LPVOID lpvInBuffer sizeof(SOCKADDR_IN), // DWORD cbInBuffer &sLocalAddr, // LPVOID lpvOUTBuffer sizeof(SOCKADDR_IN), // DWORD cbOUTBuffer &dwNumBytesReturned, // LPDWORD lpcbBytesReturned NULL, // LPWSAOVERLAPPED lpOverlapped NULL // LPWSAOVERLAPPED_COMPLETION_ROUTINE lpComplROUTINE ) == SOCKET_ERROR) { H323DBG(( DEBUG_LEVEL_ERROR, "getlocalIP error wsaioctl:%d.", WSAGetLastError() )); } else { dwLocalAddr = *(DWORD *)&sLocalAddr.sin_addr; //if the remote address is on the same machine then... H323DBG(( DEBUG_LEVEL_ERROR, "dwLocalAddr:%x.", dwLocalAddr )); if( dwLocalAddr == NET_LOCAL_IP_ADDR_INTERFACE ) { dwLocalAddr = dwRemoteAddr; } _ASSERTE( dwLocalAddr ); } closesocket( querySocket ); H323DBG(( DEBUG_LEVEL_TRACE, "GetLocalIPAddress - exited." )); return dwLocalAddr; } //!!always called from a lock BOOL RAS_CLIENT::IssueRecv(void) { int iError; WSABUF BufferArray [1]; H323DBG(( DEBUG_LEVEL_TRACE, "IssueRecv entered:%p.",this )); _ASSERTE(!m_recvOverlapped.IsPending); if(m_Socket == INVALID_SOCKET) { return FALSE; } BufferArray [0].buf = (char *)(m_recvOverlapped.arBuf); BufferArray [0].len = IO_BUFFER_SIZE; ZeroMemory (&m_recvOverlapped.Overlapped, sizeof(OVERLAPPED)); m_recvOverlapped.Type = OVERLAPPED_TYPE_RECV; m_recvOverlapped.RasClient = this; m_recvOverlapped.AddressLength = sizeof (SOCKADDR_IN); m_recvOverlapped.Flags = 0; if( WSARecvFrom(m_Socket, BufferArray, 1, &m_recvOverlapped.BytesTransferred, &m_recvOverlapped.Flags, (SOCKADDR*)&m_recvOverlapped.Address, &m_recvOverlapped.AddressLength, &m_recvOverlapped.Overlapped, NULL) == SOCKET_ERROR ) { iError = WSAGetLastError(); if( iError == WSA_IO_PENDING ) { m_recvOverlapped.IsPending = TRUE; m_IoRefCount++; } else if( iError == WSAEMSGSIZE ) { //We don't handle this condition right now as it should not happen //In future with changes in the protocol this might be invoked and //should be fixed _ASSERTE( FALSE ); } else if( iError == WSAECONNRESET ) { //On a UPD-datagram socket this error would indicate that a //previous send operation resulted in an ICMP "Port Unreachable" //message. This will happen if GK is not listening on the specified //port. This case would need special handling. _ASSERTE( FALSE ); return FALSE; } else { //fatal error on the socket. shutdown the RAS client return FALSE; } } else { //data recvd immediately. IsPending is set beacause anyway a //SendComplete event will be sent which will reset this BOOL m_recvOverlapped.IsPending = TRUE; m_IoRefCount++; } H323DBG(( DEBUG_LEVEL_TRACE, "IssueRecv exited:%p.",this )); return TRUE; } HRESULT RAS_CLIENT::EncodeSendMessage( IN RasMessage * RasMessage) { RAS_SEND_CONTEXT * SendContext; ASN1error_e AsnError; WSABUF BufferArray [1]; DWORD dwStatus; H323DBG(( DEBUG_LEVEL_TRACE, "EncodeSendMessage entered:%p.",this )); Lock(); if (m_Socket == INVALID_SOCKET) { Unlock(); return E_FAIL; } SendContext = AllocSendBuffer(); if( SendContext == NULL ) { Unlock(); return E_OUTOFMEMORY; } ZeroMemory( &SendContext -> Overlapped, sizeof (OVERLAPPED) ); AsnError = ASN1_Encode ( m_ASNCoderInfo.pEncInfo, RasMessage, RasMessage_PDU, ASN1ENCODE_SETBUFFER, SendContext -> arBuf, IO_BUFFER_SIZE); if (ASN1_FAILED (AsnError)) { H323DBG ((DEBUG_LEVEL_ERROR, "RAS: failed to encode RAS PDU (%d).", AsnError)); FreeSendBuffer (SendContext); Unlock(); return E_FAIL; } BufferArray [0].buf = (char *) SendContext -> arBuf; BufferArray [0].len = m_ASNCoderInfo.pEncInfo -> len; SendContext -> Type = OVERLAPPED_TYPE_SEND; SendContext -> RasClient = this; SendContext -> Address = m_GKAddress; if( WSASendTo (m_Socket, BufferArray, 1, &SendContext -> BytesTransferred, 0, (SOCKADDR *)&SendContext -> Address, sizeof (SOCKADDR_IN), &SendContext->Overlapped, NULL) == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) { dwStatus = WSAGetLastError(); H323DBG(( DEBUG_LEVEL_ERROR, "failed to issue async send on RAS socket" )); DumpError (dwStatus); //fatal error: shut down the client FreeSendBuffer (SendContext); Unlock(); return HRESULT_FROM_WIN32 (dwStatus); } InsertHeadList( &m_sendPendingList, &SendContext -> ListEntry ); m_IoRefCount++; Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "EncodeSendMessage exited:%p.",this )); return S_OK; } // static void NTAPI RAS_CLIENT::IoCompletionCallback( IN DWORD dwStatus, IN DWORD BytesTransferred, IN OVERLAPPED * Overlapped ) { RAS_OVERLAPPED * RasOverlapped; RAS_CLIENT * pRASClient; H323DBG(( DEBUG_LEVEL_TRACE, "ras-IoCompletionCallback entered." )); _ASSERTE( Overlapped ); RasOverlapped = CONTAINING_RECORD( Overlapped, RAS_OVERLAPPED, Overlapped ); pRASClient = RasOverlapped -> RasClient; switch (RasOverlapped -> Type) { case OVERLAPPED_TYPE_SEND: pRASClient -> OnSendComplete( dwStatus, static_cast (RasOverlapped)); break; case OVERLAPPED_TYPE_RECV: RasOverlapped -> BytesTransferred = BytesTransferred; pRASClient -> OnRecvComplete( dwStatus, static_cast (RasOverlapped)); break; default: _ASSERTE(FALSE); } H323DBG(( DEBUG_LEVEL_TRACE, "ras-IoCompletionCallback exited." )); } void RAS_CLIENT::OnSendComplete( IN DWORD dwStatus, IN RAS_SEND_CONTEXT * pSendContext ) { H323DBG(( DEBUG_LEVEL_TRACE, "OnSendComplete entered:%p.",this )); if( dwStatus != ERROR_SUCCESS ) { return; } Lock(); m_IoRefCount--; //if the RAS client is already shutdown, then reduce the I/O refcount and return. if( m_dwState == RAS_CLIENT_STATE_NONE ) { Unlock(); return; } //this buffer may have already been freed if( IsInList( &m_sendPendingList, &pSendContext->ListEntry ) ) { RemoveEntryList( &pSendContext->ListEntry ); FreeSendBuffer( pSendContext ); } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "OnSendComplete exited:%p.",this )); } void RAS_CLIENT::OnRecvComplete( IN DWORD dwStatus, IN RAS_RECV_CONTEXT * RecvContext ) { RasMessage * RasMessage = NULL; ASN1error_e AsnError; H323DBG(( DEBUG_LEVEL_TRACE, "OnRecvComplete enterd:%p.",this )); Lock(); m_IoRefCount--; //if the RAS client is already shutdown, then reduce the I/O refcount and return. if( m_dwState == RAS_CLIENT_STATE_NONE ) { Unlock(); return; } _ASSERTE(m_recvOverlapped.IsPending); m_recvOverlapped.IsPending = FALSE; switch( dwStatus ) { case ERROR_SUCCESS: //asn decode and process the message if( m_recvOverlapped.BytesTransferred != 0 ) { AsnError = ASN1_Decode ( m_ASNCoderInfo.pDecInfo, // ptr to encoder info (PVOID *) &RasMessage, // pdu data structure RasMessage_PDU, // pdu id ASN1DECODE_SETBUFFER, // flags m_recvOverlapped.arBuf, // buffer to decode m_recvOverlapped.BytesTransferred); // size of buffer to decode //issue another read IssueRecv(); if( ASN1_SUCCEEDED(AsnError) ) { _ASSERTE(RasMessage); //This function should be always called in //a lock and it unlocks the the ras client ProcessRasMessage( RasMessage ); return; } else { H323DBG(( DEBUG_LEVEL_ERROR, "RAS ASNDecode returned error:%d.", AsnError )); H323DUMPBUFFER( (BYTE*)m_recvOverlapped.arBuf, (DWORD)m_recvOverlapped.BytesTransferred); } } break; case STATUS_PORT_UNREACHABLE: case STATUS_CANCELLED: IssueRecv(); break; default: H323DBG ((DEBUG_LEVEL_ERROR, "failed to recv data on socket")); DumpError (dwStatus); break; } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "OnRecvComplete exited:%p.",this )); } int RAS_CLIENT::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 RAS_CLIENT::TermASNCoder(void) { H323DBG(( DEBUG_LEVEL_TRACE, "RAS TermASNCoder entered:%p.",this )); 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)); H323DBG(( DEBUG_LEVEL_TRACE, "RAS TermASNCoder exited:%p.",this )); return ASN1_SUCCESS; } void RAS_CLIENT::HandleRegistryChange() { PH323_ALIASNAMES pAliasList = NULL; PH323_ALIASITEM pAliasItem = NULL; PALIASCHANGE_REQUEST pAliasChangeRequest = NULL; int iIndex; H323DBG(( DEBUG_LEVEL_TRACE, "RAS HandleRegistryChange entered:%p.",this )); //If line is not in listening mode then, return if( g_pH323Line -> GetState() != H323_LINESTATE_LISTENING ) return; Lock(); __try { //If registered with a GK, and GK disabled then send URQ. if( g_RegistrySettings.fIsGKEnabled == FALSE ) { RasStop(); } else { switch( m_RegisterState ) { //If not registered then send RRQ to the GK. case RAS_REGISTER_STATE_IDLE: //No need to send URQ. //Shutdown the object. g_RasClient.Shutdown(); RasStart(); break; case RAS_REGISTER_STATE_REGISTERED: case RAS_REGISTER_STATE_RRQSENT: if( g_RegistrySettings.saGKAddr.sin_addr.s_addr != m_GKAddress.sin_addr.s_addr ) { //change of GK address //send URQ to the old GK and shutdown the RASClinet object. RasStop(); //Initialize the GK object with new settings and send RRQ to the new GK. RasStart(); } else { //check for change in alias list. for( iIndex=0; iIndex < m_pAliasList->wCount; iIndex++ ) { pAliasItem = &(m_pAliasList->pItems[iIndex]); if( pAliasItem->wType == e164_chosen ) { if( g_RegistrySettings.fIsGKLogOnPhoneEnabled == FALSE ) { break; } else if( memcmp( (PVOID)g_RegistrySettings.wszGKLogOnPhone, pAliasItem->pData, (pAliasItem->wDataLength+1) * sizeof(WCHAR) ) != 0 ) { break; } } else if( pAliasItem->wType == h323_ID_chosen ) { if( g_RegistrySettings.fIsGKLogOnAccountEnabled==FALSE ) { break; } else if( memcmp( (PVOID)g_RegistrySettings.wszGKLogOnAccount, pAliasItem->pData, (pAliasItem->wDataLength+1) * sizeof(WCHAR) ) != 0 ) { break; } } } if( (iIndex < m_pAliasList->wCount ) || ( m_pAliasList->wCount != (g_RegistrySettings.fIsGKLogOnPhoneEnabled + g_RegistrySettings.fIsGKLogOnAccountEnabled ) ) ) { //create the new alias list. pAliasList = new H323_ALIASNAMES; if( pAliasList != NULL ) { ZeroMemory( (PVOID)pAliasList, sizeof(H323_ALIASNAMES) ); if( g_RegistrySettings.fIsGKLogOnPhoneEnabled ) { if( !AddAliasItem( pAliasList, g_RegistrySettings.wszGKLogOnPhone, e164_chosen ) ) { goto cleanup; } } if( g_RegistrySettings.fIsGKLogOnAccountEnabled ) { if( !AddAliasItem( pAliasList, g_RegistrySettings.wszGKLogOnAccount, h323_ID_chosen ) ) { goto cleanup; } } //queue the alias change request in the list pAliasChangeRequest = new ALIASCHANGE_REQUEST; if( pAliasChangeRequest == NULL ) { goto cleanup; } pAliasChangeRequest->rasEndpointID.length = m_RASEndpointID.length; CopyMemory( (PVOID)pAliasChangeRequest->rasEndpointID.value, m_RASEndpointID.value, (pAliasChangeRequest->rasEndpointID.length+1)*sizeof(WCHAR) ); pAliasChangeRequest->wRequestSeqNum = 0; pAliasChangeRequest->pAliasList = pAliasList; //Send RRQ with the new alias list. if( !SendRRQ(NOT_RESEND_SEQ_NUM, pAliasChangeRequest) ) { goto cleanup; } InsertHeadList( &m_aliasChangeRequestList, &pAliasChangeRequest->listEntry ); } } } break; default: //Shutdown the RASClinet object. Send RRQ to new GK. RasStop(); RasStart(); break; } } } __except(1) { H323DBG(( DEBUG_LEVEL_TRACE, "except in HandleRegistryChange :%p.", this )); _ASSERTE(0); } Unlock(); H323DBG(( DEBUG_LEVEL_TRACE, "RAS HandleRegistryChange exited:%p.", this )); return; cleanup: if( pAliasList != NULL ) { FreeAliasNames( pAliasList ); } if( pAliasChangeRequest != NULL ) { delete pAliasChangeRequest; } Unlock(); }