#include "stdafx.h" #include "cbridge.h" // SOURCE_Q931_INFO methods /* virtual */ SOURCE_Q931_INFO::~SOURCE_Q931_INFO( ) { } // this should never get called, but needs to be supported // as the base class implementation is pure virtual // virtual HRESULT SOURCE_Q931_INFO::AcceptCallback ( IN DWORD Status, IN SOCKET Socket, IN SOCKADDR_IN * LocalAddress, IN SOCKADDR_IN * RemoteAddress) { // we should never receive an accept call back for the // Q931 source instance _ASSERTE(FALSE); return E_UNEXPECTED; } // This function is called by the event manager. // The caller will free the PDU. This function may modify // some of the fields of the PDU. // this is called when an async receive operation completes // virtual HRESULT SOURCE_Q931_INFO::ReceiveCallback ( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { HRESULT HResult; // we must have valid decoded PDUs _ASSERTE(NULL != pQ931Message); // The ASN.1 part is not present in the case of some PDUs //_ASSERTE(NULL != pH323UserInfo); // if RELEASE COMPLETE PDU if (pH323UserInfo != NULL && releaseComplete_chosen == pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { DebugF (_T("Q931: 0x%x caller sent 'Release Complete'.\n"), &GetCallBridge ()); HResult = HandleReleaseCompletePDU( pQ931Message, pH323UserInfo ); return HResult; } // check current state and handle the incoming PDU switch(m_Q931SourceState) { case Q931_SOURCE_STATE_CON_ESTD: { // processes PDUs when in Q931_SOURCE_STATE_CON_ESTD state HResult = HandleStateSrcConEstd( pQ931Message, pH323UserInfo ); } break; case Q931_SOURCE_STATE_SETUP_RCVD: { // Pass on the PDU to the Q931 destination instance which // passes it on after due modifications HResult = GetDestQ931Info().ProcessSourcePDU( pQ931Message, pH323UserInfo ); } break; case Q931_SOURCE_STATE_INIT: case Q931_SOURCE_STATE_REL_COMP_RCVD: default: { // we can't be in Q931_SOURCE_STATE_INIT as we wouldn't have // queued an async receive by then // we can't be in Q931_SOURCE_STATE_REL_COMP_RCVD as we not have // queued this receive // I.K. 0819999 _ASSERTE(FALSE); HResult = E_UNEXPECTED; } break; }; // if there is an error if (FAILED(HResult)) { goto shutdown; } // we must queue an async receive irrespective of whether // the PDU was dropped (IPTEL_E_INVALID_PDU == HResult) // queue an async receive HResult = QueueReceive(); if (FAILED(HResult)) { goto shutdown; } return HResult; shutdown: // initiate shutdown GetCallBridge().Terminate (); return HResult; } // handles RELEASE_COMPLETE PDUs HRESULT SOURCE_Q931_INFO::HandleReleaseCompletePDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { // it must be a release complete PDU _ASSERTE(releaseComplete_chosen == \ pH323UserInfo->h323_uu_pdu.h323_message_body.choice); // we can handle a RELEASE COMPLETE PDU in any state except the following _ASSERTE(Q931_SOURCE_STATE_INIT != m_Q931SourceState); _ASSERTE(Q931_SOURCE_STATE_REL_COMP_RCVD != m_Q931SourceState); // pass on the pdu to the Q931 source instance // ignore return error code, if any GetDestQ931Info().ProcessSourcePDU( pQ931Message, pH323UserInfo ); // state transition to Q931_SOURCE_STATE_REL_COMP_RCVD m_Q931SourceState = Q931_SOURCE_STATE_REL_COMP_RCVD; // initiate shutdown - this cancels the timers, but doesn't close // the sockets. the sockets are closed when the send callback is made GetCallBridge().TerminateCallOnReleaseComplete(); GetSocketInfo ().Clear (TRUE); return S_OK; } // processes PDUs when in Q931_SOURCE_STATE_CON_EST state HRESULT SOURCE_Q931_INFO::HandleStateSrcConEstd( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { if (!pH323UserInfo) { DebugF(_T("SOURCE_Q931_INFO::HandleStateSrcConEstd: no UUIE data! ignoring message.\n")); return E_INVALIDARG; } // we can only handle a setup PDU in this state // all other PDUs are THROWN AWAY (as we don't know // whom to pass it to) if (setup_chosen != pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { DebugF( _T("SOURCE_Q931_INFO::HandleStateSrcConEstd: received a pdu other than Setup before receiving a Setup, pdu cannot be processed\n")); return E_INVALIDARG; } // save the caller's call reference value now as we may reuse the // PDU structure in ProcessSourcePDU // The Setup PDU is sent by the originator and so the call reference flag // should not be set. // -XXX- this should not be an assert!!!! FIX THIS! -- arlied _ASSERTE(!(pQ931Message->CallReferenceValue & CALL_REF_FLAG)); m_CallRefVal = pQ931Message->CallReferenceValue | CALL_REF_FLAG; // pass on the setup pdu to the Q931 destination instance HRESULT HResult = GetDestQ931Info().ProcessSourcePDU( pQ931Message, pH323UserInfo ); if (FAILED (HResult)) { return HResult; } // state transition to Q931_SOURCE_STATE_SETUP_RCVD m_Q931SourceState = Q931_SOURCE_STATE_SETUP_RCVD; // try to create a CALL PROCEEDING PDU // if we fail, don't try to recover // Q.931 requires that gateways in the call path must identify // themselves to the callee Q931_MESSAGE CallProcQ931Message; H323_UserInformation CallProcH323UserInfo; HResult = Q931EncodeCallProceedingMessage( m_CallRefVal, &CallProcQ931Message, &CallProcH323UserInfo ); // try to send a CALL PROCEEDING PDU to the caller // if we fail, don't try to recover HResult = QueueSend( &CallProcQ931Message, &CallProcH323UserInfo); return HResult; } // TimerValue contains the timer value in seconds, for a timer event // to be created when a queued send completes HRESULT SOURCE_Q931_INFO::ProcessDestPDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { HRESULT HResult = E_FAIL; // handle PDU from the source Q931 instance switch(m_Q931SourceState) { case Q931_SOURCE_STATE_SETUP_RCVD: { if (connect_chosen == pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { DebugF (_T("Q931: 0x%x forwarding 'Connect' to caller.\n"), &GetCallBridge ()); HResult = ProcessConnectPDU( pQ931Message, pH323UserInfo ); if (FAILED(HResult)) { DebugF(_T("SOURCE_Q931_INFO::ProcessDestPDU: ProcessConnectPDU failed, returning %x\n"), HResult); return HResult; } } } break; case Q931_SOURCE_STATE_INIT: case Q931_SOURCE_STATE_CON_ESTD: case Q931_SOURCE_STATE_REL_COMP_RCVD: default: { DebugF( _T("SOURCE_Q931_INFO::ProcessDestPDU: bogus state, returning E_UNEXPECTED\n")); return E_UNEXPECTED; } break; }; // Q931 Header - CallReferenceValue // pQ931Message->CallReferenceValue = GetCallRefVal(); // queue async send for the PDU HResult = QueueSend(pQ931Message, pH323UserInfo); if (HResult != S_OK) { DebugF( _T("SOURCE_Q931_INFO::ProcessDestPDU: failed to queue sendreturning %x\n"), HResult); return HResult; } return HResult; } // NOTE: CRV modification is handled in ProcessDestPDU HRESULT SOURCE_Q931_INFO::ProcessConnectPDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { Connect_UUIE * Connect; HRESULT Result; SOCKADDR_IN H245ListenAddress; // it must be a CONNECT PDU _ASSERTE(connect_chosen == pH323UserInfo->h323_uu_pdu.h323_message_body.choice); Connect = &pH323UserInfo -> h323_uu_pdu.h323_message_body.u.connect; // we must have already checked to see if an h245 transport // address was specified by the callee in the dest instance _ASSERTE(Connect_UUIE_h245Address_present & Connect -> bit_mask); _ASSERTE(ipAddress_chosen & Connect -> h245Address.choice); // queue an overlapped accept, get ready to accept an incoming // connection on the local address/port H245ListenAddress.sin_addr.s_addr = htonl (GetCallBridge (). GetSourceInterfaceAddress ()); H245ListenAddress.sin_port = htons (0); Result = GetSourceH245Info().ListenForCaller (&H245ListenAddress); if (FAILED (Result)) { DebugF (_T("H245: 0x%x failed to listen for caller.\n"), &GetCallBridge ()); return Result; } //_ASSERTE(S_FALSE != HResult); // replace the h245 address/port in the connect PDU FillTransportAddress (H245ListenAddress, Connect -> h245Address); DebugF (_T("H245: 0x%x listens for H.245 connection from caller on %08X:%04X.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (&H245ListenAddress)); return S_OK; }