/*++ Copyright (c) 1998 - 2000 Microsoft Corporation Module Name: dstq931.cpp Abstract: Methods for processing Q.931 messages to/from destination side of a H.323 connection. Revision History: --*/ #include "stdafx.h" DEST_Q931_INFO::~DEST_Q931_INFO ( void ) /*++ Routine Description: Constructor for DEST_Q931_INFO class Arguments: None Return Values: None Notes: Virtual --*/ { // release the allocated call reference value // 0 is not a valid call ref value // Note that the CRV is allocated for both incoming as well as // outgoing calls. if (m_CallRefVal != 0) { DeallocCallRefVal(m_CallRefVal); } } HRESULT DEST_Q931_INFO::AcceptCallback ( IN DWORD Status, IN SOCKET Socket, IN SOCKADDR_IN * LocalAddress, IN SOCKADDR_IN * RemoteAddress ) /*++ Routine Description: Routine invoked when Q.931 connection is asynchronously accepted Arguments: Status -- status code of the asynchronous accept operation Socket -- handle of the socket on which the accept completed LocalAddress - address of the local socket that accepted the connection RemoteAddress - address of the remote socket that initiated the connection Return Values: Result of processing the accept completion Notes: 1. Virtual 2. Currently there are not codepaths that would invoke the method. It is only provided because the base class declares the function as virtual. --*/ { DebugF (_T("Q931: AcceptCallback: status %08XH socket %08XH local address %08X:%04X remote address %08X:%04X) called.\n"), Status, Socket, ntohl (LocalAddress -> sin_addr.s_addr), ntohs (LocalAddress -> sin_port), ntohl (RemoteAddress -> sin_addr.s_addr), ntohs (RemoteAddress -> sin_port)); // we don't yet have any code that'll result in this method // getting called _ASSERTE(FALSE); // CHECK_TERMINATION; return E_UNEXPECTED; } HRESULT DEST_Q931_INFO::ReceiveCallback ( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) /*++ Routine Description: Routine invoked when Q.931 receive from the network completes. Arguments: pQ931Message -- Q.931 message received from the network pH323UserInfo - ASN.1-encoded part of the Q.931 message Return Values: Result of processing the received Q.931 message Notes: Virtual --*/ { HRESULT HResult; // CHECK_TERMINATION; // we must have valid decoded PDUs _ASSERTE(NULL != pQ931Message); _ASSERTE(NULL != pH323UserInfo); // CODEWORK: Ensure that this message has an ASN part // i.e. pH323UserInfo != NULL // if RELEASE COMPLETE PDU if (pH323UserInfo != NULL && releaseComplete_chosen == pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { DebugF (_T("Q931: 0x%x callee sent 'Release Complete'.\n"), &GetCallBridge ()); HResult = HandleReleaseCompletePDU( pQ931Message, pH323UserInfo ); return HResult; } // handle new PDU from the remote end switch(m_Q931DestState) { case Q931_DEST_STATE_CON_ESTD: { // processes PDUs when in Q931_DEST_STATE_CON_EST state HResult = HandleStateDestConEstd( pQ931Message, pH323UserInfo ); } break; case Q931_DEST_STATE_CALL_PROC_RCVD: { // processes PDUs when in Q931_DEST_STATE_CALL_PROC_RCVD state HResult = HandleStateDestCallProcRcvd( pQ931Message, pH323UserInfo ); } break; case Q931_DEST_STATE_ALERTING_RCVD: { // processes PDUs when in Q931_DEST_STATE_ALERTING_RCVD state HResult = HandleStateDestAlertingRcvd( pQ931Message, pH323UserInfo ); } break; case Q931_DEST_STATE_CONNECT_RCVD: { // processes PDUs when in Q931_DEST_STATE_CONNECT_RCVD state HResult = HandleStateDestConnectRcvd( pQ931Message, pH323UserInfo ); } break; case Q931_DEST_STATE_INIT: case Q931_DEST_STATE_REL_COMP_RCVD: default: { // we cannot be in Q931_DEST_STATE_INIT as we wouldn't have // queued an async receive by then // we cannot be in Q931_DEST_STATE_REL_COMP_RCVD as we would // not have queue an async receive on transitioning to this state // Commenting out the assert below is fix for #389657 // _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 previous // PDU was dropped HResult = QueueReceive(); if (FAILED(HResult)) { goto shutdown; } //_ASSERTE(S_FALSE != HResult); return HResult; shutdown: // initiate shutdown GetCallBridge().Terminate (); return HResult; } HRESULT DEST_Q931_INFO::HandleStateDestConEstd ( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) /*++ Routine Description: Processes Q.931 PDUs when in Q931_DEST_STATE_CON_ESTD state. CALL_PROCEEDING, ALERTING and CONNECT PDUs are handled here. Any other PDU is simply passed on to the Q931 source instance Arguments: pQ931Message -- Q.931 message received from the network pH323UserInfo - ASN.1-encoded part of the Q.931 message Return Values: Result of the PDU processing Notes: --*/ { HRESULT HResult = E_FAIL; // check PDU type switch (pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { case callProceeding_chosen : // CALL_PROCEEDING DebugF (_T("Q931: 0x%x callee sent 'Call Proceeding'.\n"), &GetCallBridge ()); HResult = HandleCallProceedingPDU( pQ931Message, pH323UserInfo ); break; case alerting_chosen : // ALERTING DebugF (_T("Q931: 0x%x callee sent 'Alerting'.\n"), &GetCallBridge ()); HResult = HandleAlertingPDU( pQ931Message, pH323UserInfo ); break; case connect_chosen : // CONNECT DebugF (_T("Q931: 0x%x callee sent 'Connect'.\n"), &GetCallBridge ()); HResult = HandleConnectPDU( pQ931Message, pH323UserInfo ); break; default: // everything else // pass on the pdu to the Q931 source instance DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"), &GetCallBridge (), pH323UserInfo->h323_uu_pdu.h323_message_body.choice); HResult = GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); break; }; return HResult; } HRESULT DEST_Q931_INFO::HandleCallProceedingPDU ( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) /*++ Routine Description: Handles CALL PROCEEDING PDU Arguments: IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo Return Values: Result of PDU processing --*/ { HRESULT HResult = E_FAIL; // for fast connect do the following // if there is h245 info and no current h245 connection // handle it (save it, establish connection etc.) // state transition to Q931_DEST_STATE_CONNECT_RCVD // else // create new timer for ALERTING // state transition to Q931_DEST_STATE_CALL_PROC_RCVD HResult = GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); if (FAILED (HResult)) { return HResult; } _ASSERTE(S_OK == HResult); // cancel current timer (there MUST be one) // we can only cancel the timer at this point, as we may drop the // PDU anytime before this //_ASSERTE(NULL != m_TimerHandle); TimprocCancelTimer(); DebugF (_T("Q931: 0x%x cancelled timer.\n"), &GetCallBridge ()); HResult = CreateTimer(Q931_POST_CALL_PROC_TIMER_VALUE); if (FAILED(HResult)) { DebugF (_T("Q931: 0x%x failed to create timer for duration %d milliseconds.('Call Proceeding'). Error - %x.\n"), &GetCallBridge (), Q931_POST_CALL_PROC_TIMER_VALUE, HResult); return HResult; } DebugF (_T("Q931: 0x%x created timer for duration %d milliseconds.('Call Proceeding').\n"), &GetCallBridge (), Q931_POST_CALL_PROC_TIMER_VALUE); m_Q931DestState = Q931_DEST_STATE_CALL_PROC_RCVD; return S_OK; } // handles Alerting PDUs HRESULT DEST_Q931_INFO::HandleAlertingPDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { HRESULT HResult = E_FAIL; // for fast connect do the following // if there is h245 info and no current h245 connection // handle it (save it, establish connection etc.) // state transition to Q931_DEST_STATE_CONNECT_RCVD // else // create new timer for CONNECT // state transition to Q931_DEST_STATE_ALERTING_RCVD HResult = GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); if (FAILED(HResult)) { return HResult; } _ASSERTE(S_OK == HResult); // cancel current timer (there MUST be one) // we can only cancel the timer at this point, as we may drop the // PDU anytime before this //_ASSERTE(NULL != m_TimerHandle); TimprocCancelTimer(); DebugF (_T("Q931: 0x%x cancelled timer.\n"), &GetCallBridge ()); HResult = CreateTimer(Q931_POST_ALERTING_TIMER_VALUE); if (FAILED(HResult)) { DebugF (_T("Q931: 0x%x failed to create timer for duration %d milliseconds('Alerting'). Error - %x.\n"), &GetCallBridge (), Q931_POST_ALERTING_TIMER_VALUE, HResult); return HResult; } DebugF (_T("Q931: 0x%x created timer for duration %d milliseconds ('Alerting').\n"), &GetCallBridge (), Q931_POST_ALERTING_TIMER_VALUE); m_Q931DestState = Q931_DEST_STATE_ALERTING_RCVD; return HResult; } // handles CONNECT PDUs HRESULT DEST_Q931_INFO::HandleConnectPDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { Connect_UUIE * Connect; HRESULT HResult = E_FAIL; SOCKADDR_IN H245CalleeAddress; // it has to 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 cannot have an earlier h245 connection _ASSERTE(m_pH323State->GetH245Info().GetSocketInfo().Socket == INVALID_SOCKET); // if the pdu doesn't have h245 info or a non-ip address is sent if (!(Connect_UUIE_h245Address_present & Connect -> bit_mask) || !(ipAddress_chosen == Connect -> h245Address.choice)) { // TO DO ** send back a release complete // go to shutdown mode DebugF (_T("Q931: 0x%x addressing information missing or bogus, rejecting 'Connect' PDU.\n"), &GetCallBridge()); return E_INVALIDARG; } // convert the destination H.245 transport address to address (dword), // port (word) HResult = GetTransportInfo( pH323UserInfo->h323_uu_pdu.h323_message_body.u.connect.h245Address, H245CalleeAddress); if (HResult != S_OK) { return HResult; } // Pass it on to the source Q931 instance HResult = GetSourceQ931Info().ProcessDestPDU (pQ931Message, pH323UserInfo); if (HResult != S_OK) { return HResult; } // save the destination's H.245 address/port // when the source responds by connecting to our sent address/port, // we'll connect to the destination's sent address/port GetDestH245Info().SetCalleeInfo (&H245CalleeAddress); DebugF (_T("H245: 0x%x will make H.245 connection to %08X:%04X.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (&H245CalleeAddress)); // cancel current timer (there MUST be one) // we can only cancel the timer at this point, as we may drop the // PDU anytime before this //_ASSERTE(NULL != m_TimerHandle); TimprocCancelTimer(); DebugF (_T("Q931: 0x%x cancelled timer.\n"), &GetCallBridge ()); // state transition to Q931_DEST_STATE_CONNECT_RCVD m_Q931DestState = Q931_DEST_STATE_CONNECT_RCVD; return HResult; } // handles RELEASE_COMPLETE PDUs HRESULT DEST_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_DEST_STATE_INIT != m_Q931DestState); _ASSERTE(Q931_DEST_STATE_REL_COMP_RCVD != m_Q931DestState); // cancel current timer if any // pass on the pdu to the Q931 source instance // ignore return error code, if any GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); // state transition to Q931_DEST_STATE_REL_COMP_RCVD m_Q931DestState = Q931_DEST_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_DEST_STATE_CALL_PROC_RCVD state HRESULT DEST_Q931_INFO::HandleStateDestCallProcRcvd( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { // we can handle ALERTING and CONNECT // PDUs here. Any other PDU is simply passed on to the // Q931 source instance HRESULT HResult; switch (pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { case alerting_chosen : // ALERTING { DebugF (_T("Q931: 0x%x callee sent 'Alerting'.\n"), &GetCallBridge ()); HResult = HandleAlertingPDU( pQ931Message, pH323UserInfo ); } break; case connect_chosen : // CONNECT { DebugF (_T("Q931: 0x%x callee sent 'Connect'.\n"), &GetCallBridge ()); HResult = HandleConnectPDU( pQ931Message, pH323UserInfo ); } break; default: { DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"), &GetCallBridge (), pH323UserInfo->h323_uu_pdu.h323_message_body.choice); // pass on the pdu to the Q931 source instance HResult = GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); } break; }; return HResult; } // processes PDUs when in Q931_DEST_STATE_ALERTING_RCVD state HRESULT DEST_Q931_INFO::HandleStateDestAlertingRcvd( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { // we can handle CONNECT and RELEASE_COMPLETE // PDUs here. Any other PDU is simply passed on to the // Q931 source instance HRESULT HResult = E_FAIL; switch (pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { case connect_chosen : // CONNECT { DebugF (_T("Q931: 0x%x callee sent 'Connect'.\n"), &GetCallBridge ()); HResult = HandleConnectPDU( pQ931Message, pH323UserInfo ); } break; default: { // pass on the pdu to the Q931 source instance DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"), &GetCallBridge (), pH323UserInfo->h323_uu_pdu.h323_message_body.choice); HResult = GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); } break; }; return HResult; } // processes PDUs when in Q931_DEST_STATE_CONNECT_RCVD state HRESULT DEST_Q931_INFO::HandleStateDestConnectRcvd( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { // all PDUs are simply passed on to the Q931 source instance HRESULT HResult = E_FAIL; DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"), &GetCallBridge (), pH323UserInfo->h323_uu_pdu.h323_message_body.choice); // pass on the pdu to the Q931 source instance HResult = GetSourceQ931Info().ProcessDestPDU( pQ931Message, pH323UserInfo ); return HResult; } HRESULT DEST_Q931_INFO::ProcessSourcePDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { // handle PDU from the source Q931 instance switch(m_Q931DestState) { case Q931_DEST_STATE_INIT: { HRESULT HResult = E_FAIL; // we can only handle the SETUP PDU in this state // establishes Q931 connection, forwards the SETUP PDU and // queues the first async receive on the new socket DebugF (_T("Q931: 0x%x caller sent 'Setup'.\n"), &GetCallBridge ()); HResult = ProcessSourceSetupPDU( pQ931Message, pH323UserInfo ); return HResult; } case Q931_DEST_STATE_CON_ESTD: case Q931_DEST_STATE_CALL_PROC_RCVD: case Q931_DEST_STATE_ALERTING_RCVD: case Q931_DEST_STATE_CONNECT_RCVD: { // pass on the PDU after modifications DebugF (_T("Q931: 0x%x caller sent PDU (type %d). Forwarding without processing.\n"), &GetCallBridge (), pH323UserInfo->h323_uu_pdu.h323_message_body.choice); } break; case Q931_DEST_STATE_REL_COMP_RCVD: default: { return E_UNEXPECTED; } break; }; // we come here only if we fall through the switch statement // Q931 Header - change CallReferenceValue // pQ931Message->CallReferenceValue = GetCallRefVal(); // queue async send for the PDU HRESULT HResult = E_FAIL; HResult = QueueSend(pQ931Message, pH323UserInfo); if (FAILED(HResult)) { return HResult; } return HResult; } HRESULT DEST_Q931_INFO::ProcessSourceSetupPDU( IN Q931_MESSAGE *pQ931Message, IN H323_UserInformation *pH323UserInfo ) { Setup_UUIE * Setup; HRESULT Result; ULONG Error; SOCKADDR_IN DestinationAddress = {0}; DWORD TranslatedDestinationAddress = 0; AliasAddress * Alias; ANSI_STRING AnsiAlias; ASN1uint32_t OldFastStartBit = 0U; ASN1uint32_t OldH245TunnelingBit = 0U; ASN1bool_t OldH245TunnelingFlag = FALSE; GetCallBridge ().GetDestinationAddress (&DestinationAddress); _ASSERTE(Q931_DEST_STATE_INIT == m_Q931DestState); // it has to be a Setup PDU if (setup_chosen != pH323UserInfo->h323_uu_pdu.h323_message_body.choice) { DebugF(_T("Q931: 0x%x in Setup PDU UUIE is not a Setup-UUIE, rejecting PDU.\n"), &GetCallBridge ()); return E_UNEXPECTED; } Setup = &pH323UserInfo -> h323_uu_pdu.h323_message_body.u.setup; // Generate the Call Reference Value for both incoming/outgoing calls if (!AllocCallRefVal(m_CallRefVal)) { DebugF(_T("Q931: 0x%x failed to allocate call reference value.\n"), &GetCallBridge ()); return E_UNEXPECTED; } // examine the alias from the Setup-UUIE, query the LDAP translation table if (Setup -> bit_mask & destinationAddress_present && Setup -> destinationAddress) { CHAR AnsiAliasValue [0x100]; INT Length; Alias = &Setup -> destinationAddress -> value; switch (Alias -> choice) { case h323_ID_chosen: // the expected case // downgrade to ANSI Length = WideCharToMultiByte (CP_ACP, 0, (LPWSTR)Alias -> u.h323_ID.value, Alias -> u.h323_ID.length, AnsiAliasValue, 0xFF, NULL, NULL); if (!Length) { DebugF (_T("Q931: 0x%x failed to convert unicode string. Internal error.\n"), &GetCallBridge ()); return E_FAIL; } AnsiAliasValue [Length] = 0; AnsiAlias.Buffer = AnsiAliasValue; AnsiAlias.Length = Length * (USHORT)sizeof (CHAR); break; case email_ID_chosen: AnsiAlias.Buffer = Alias -> u.email_ID; AnsiAlias.Length = (USHORT) strlen (Alias -> u.email_ID) * sizeof (CHAR); break; case e164_chosen: AnsiAlias.Buffer = Alias -> u.e164; AnsiAlias.Length = (USHORT) strlen (Alias -> u.e164) * sizeof (CHAR); break; default: DebugF (_T("Q931: 0x%x bogus alias address type.\n"), &GetCallBridge()); return E_FAIL; } Result = LdapQueryTableByAlias (&AnsiAlias, &TranslatedDestinationAddress); if (Result == S_OK) { DebugF (_T("Q931: 0x%x resolved alias (%.*S) to address %08X.\n"), &GetCallBridge (), ANSI_STRING_PRINTF (&AnsiAlias), TranslatedDestinationAddress); // Change the initial destination address to the one read from // the LDAP Address Translation Table DestinationAddress.sin_addr.s_addr = htonl (TranslatedDestinationAddress); } else { DebugF (_T("Q931: 0x%x failed to resolve alias (%.*S) in LDAP table.\n"), &GetCallBridge (), ANSI_STRING_PRINTF (&AnsiAlias)); } } else { DebugF (_T("Q931: 0x%x destination not specified. Looking in registry for special destination.\n"), &GetCallBridge ()); Result = LookupDefaultDestination (&TranslatedDestinationAddress); if (Result == S_OK) { DestinationAddress.sin_addr.s_addr = htonl (TranslatedDestinationAddress); DebugF (_T("Q931: 0x%x found special destination in registry.\n"), &GetCallBridge ()); } else { DebugF (_T("Q931: 0x%x did not find special destination in registry.\n"), &GetCallBridge ()); } } DebugF (_T("Q931: 0x%x will use address %08X:%04X as destination.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (&DestinationAddress)); Error = GetBestInterfaceAddress (ntohl (DestinationAddress.sin_addr.s_addr), &GetCallBridge ().DestinationInterfaceAddress); if (ERROR_SUCCESS != Error) { DebugF (_T("Q931: 0x%x failed to determine destination interface address for %08X:%04X.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (&DestinationAddress)); return HRESULT_FROM_WIN32 (Error); } Result = ConnectToH323Endpoint (&DestinationAddress); if (Result != S_OK) { DebugF (_T("Q931: 0x%x failed to connect to address %08X:%04X.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (&DestinationAddress)); return E_FAIL; } // If the call succeeds, then the connection to the destination is // established. So, the Q.931 PDU can be modified and sent to the // destination. // Q931 Header - CallReferenceValue // pQ931Message->CallReferenceValue = GetCallRefVal(); // H323UserInfo - // destCallSignalAddress TransportAddress OPTIONAL // sourceCallSignalAddress TransportAddress OPTIONAL // if the destCallSignalAddress is set, replace it with the // remote ip v4 address, port if (Setup -> bit_mask & Setup_UUIE_destCallSignalAddress_present) { FillTransportAddress ( m_SocketInfo.RemoteAddress, Setup -> destCallSignalAddress); } // if the sourceCallSignalAddress is set, replace it with // own ip v4 address, port if (Setup -> bit_mask & sourceCallSignalAddress_present) { FillTransportAddress ( m_SocketInfo.LocalAddress, Setup -> sourceCallSignalAddress); } // if ANY of the fields in the extension field are set, // then make sure that all of the mandatory extension fields // are set. this is a workaround for a problem caused by // inconsistent ASN.1 files. -- arlied if ((sourceCallSignalAddress_present | Setup_UUIE_remoteExtensionAddress_present | Setup_UUIE_callIdentifier_present | h245SecurityCapability_present | Setup_UUIE_tokens_present | Setup_UUIE_cryptoTokens_present | Setup_UUIE_fastStart_present | canOverlapSend_present | mediaWaitForConnect_present ) & Setup -> bit_mask) { // check each mandatory field // fill in quasi-bogus values for those that the source did not supply if (!(Setup -> bit_mask & Setup_UUIE_callIdentifier_present)) { Debug (_T("Q931: *** warning, source did NOT fill in the mandatory callIdentifier field! using zeroes\n")); ZeroMemory (Setup -> callIdentifier.guid.value, sizeof (GUID)); Setup -> callIdentifier.guid.length = sizeof (GUID); Setup -> bit_mask |= Setup_UUIE_callIdentifier_present; } if (!(Setup -> bit_mask & canOverlapSend_present)) { Debug (_T("Q931: *** warning, source did NOT fill in the mandatory canOverlapSend field! using value of FALSE\n")); Setup -> canOverlapSend = FALSE; Setup -> bit_mask |= canOverlapSend_present; } if (!(Setup -> bit_mask & mediaWaitForConnect_present)) { Debug (_T("Q931: *** warning, source did NOT fill in the mandatory mediaWaitForConnect field! using value of FALSE\n")); Setup -> mediaWaitForConnect = FALSE; Setup -> bit_mask |= mediaWaitForConnect_present; } // We don't support FastStart procedures for now // Save the information on whether fastStart element was present: it will // have to be restored later. OldFastStartBit = Setup -> bit_mask & Setup_UUIE_fastStart_present; // Now unconditionally turn off FastStart Setup -> bit_mask &= ~Setup_UUIE_fastStart_present; } // We don't support H.245 Tunneling // Save the information on whether this PDU contained H.245 tunneled data: it will // have to be restored later. OldH245TunnelingBit = pH323UserInfo -> h323_uu_pdu.bit_mask & h245Tunneling_present; OldH245TunnelingFlag = pH323UserInfo -> h323_uu_pdu.h245Tunneling; // Now unconditionally turn off H.245 tunneling pH323UserInfo -> h323_uu_pdu.bit_mask &= ~h245Tunneling_present; pH323UserInfo -> h323_uu_pdu.h245Tunneling = FALSE; // queue async send for SETUP PDU Result = QueueSend(pQ931Message, pH323UserInfo); if (FAILED(Result)) { DebugF (_T("Q931: 0x%x failed to queue send.\n"), &GetCallBridge ()); goto cleanup; } // Need to restore information about FastStart and H.245 tunneling so that the // Setup PDU is properly deallocated by the ASN.1 module Setup -> bit_mask |= OldFastStartBit; pH323UserInfo -> h323_uu_pdu.bit_mask |= OldH245TunnelingBit; pH323UserInfo -> h323_uu_pdu.h245Tunneling = OldH245TunnelingFlag; // since the socket was created just now, we must // queue the first async receive Result = QueueReceive(); if (FAILED(Result)) { DebugF (_T("Q931: 0x%x failed to queue receive.\n"), &GetCallBridge()); goto cleanup; } Result = CreateTimer (Q931_POST_SETUP_TIMER_VALUE); if (FAILED(Result)) { DebugF (_T("Q931: 0x%x failed to create timer for duration %d milliseconds ('Setup'). Error - %x.\n"), &GetCallBridge (), Q931_POST_SETUP_TIMER_VALUE, Result); goto cleanup; } DebugF (_T("Q931: 0x%x created timer for duration %d milliseconds('Setup').\n"), &GetCallBridge (), Q931_POST_SETUP_TIMER_VALUE); // state transition to Q931_DEST_STATE_CON_ESTD m_Q931DestState = Q931_DEST_STATE_CON_ESTD; return Result; cleanup: m_SocketInfo.Clear(TRUE); return Result; } #define IPV4_ADDR_MAX_LEN 0x10 // max length of quad-dotted representation of an IP address HRESULT DEST_Q931_INFO::LookupDefaultDestination ( OUT DWORD * ReturnAddress) // host order { TCHAR szDefaultLocalDestAddr [IPV4_ADDR_MAX_LEN]; LONG Result; DWORD ValueLength; DWORD Type; HKEY Key; SOCKADDR_IN Address = { 0 }; INT AddressLength = sizeof(SOCKADDR_IN); // 1. Open the registry key containing the proxy's parameters Result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, H323ICS_SERVICE_PARAMETERS_KEY_PATH, 0, KEY_READ, &Key); if (Result != ERROR_SUCCESS) { DebugF(_T("Q931: 0x%x could not open registry parameter key. Error: %d(0x%x)"), &GetCallBridge (), Result, Result); return Result; } // 2. Read the value of the default destination on the local subnet ValueLength = sizeof (szDefaultLocalDestAddr); Result = RegQueryValueEx ( Key, H323ICS_REG_VAL_DEFAULT_LOCAL_DEST_ADDR, 0, &Type, (LPBYTE) szDefaultLocalDestAddr, &ValueLength); if (Result != ERROR_SUCCESS || Type != REG_SZ) { szDefaultLocalDestAddr[0] = '\0'; RegCloseKey (Key); return S_FALSE; } // 3. Close the registry key for the proxy parameters RegCloseKey (Key); // 4. Convert the string with the IP address of the default // destination on the local subnet to its binary representation Result = WSAStringToAddress( szDefaultLocalDestAddr, AF_INET, NULL, (SOCKADDR *) &Address, &AddressLength ); if (Result != ERROR_SUCCESS) { DebugF (_T("Q931: Bogus address (%S).\n"), szDefaultLocalDestAddr); return Result; } // 5. Prepare the return address in host order *ReturnAddress = htonl (Address.sin_addr.s_addr); return ERROR_SUCCESS; } HRESULT DEST_Q931_INFO::ConnectToH323Endpoint( IN SOCKADDR_IN * DestinationAddress) { INT Status; // Connect to the destination specifed by the client (for outbound calls) // or to the selected destination on the local subnet (for inbound calls) Status = m_SocketInfo.Connect (DestinationAddress); if (Status == 0) { DebugF (_T ("Q931: 0x%x successfully connected to %08X:%04X.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (DestinationAddress)); return S_OK; } else { DebugErrorF (Status, _T("Q931: 0x%x failed to connect to %08X:%04X.\n"), &GetCallBridge (), SOCKADDR_IN_PRINTF (DestinationAddress)); return HRESULT_FROM_WIN32 (Status); } }