/*++ Copyright (c) 1997 Microsoft Corporation Module Name: channel.c Abstract: Routines to manipulate H.245 logical channels. Environment: User Mode - Win32 Revision History: --*/ /////////////////////////////////////////////////////////////////////////////// // // // Include files // // // /////////////////////////////////////////////////////////////////////////////// #include "globals.h" #include "termcaps.h" #include "callback.h" #include "line.h" /////////////////////////////////////////////////////////////////////////////// // // // Private procedures // // // /////////////////////////////////////////////////////////////////////////////// BOOL H323ResetChannel( PH323_CHANNEL pChannel ) /*++ Routine Description: Resets channel object original state for re-use. Arguments: pChannel - Pointer to channel object to reset. Return Values: Returns true if successful. --*/ { // change channel state to allocated pChannel->nState = H323_CHANNELSTATE_ALLOCATED; // initialize stream description memset(&pChannel->Settings,0,sizeof(STREAMSETTINGS)); // uninitialize msp channel handle pChannel->hmChannel = NULL; // uninitialize channel handle pChannel->hccChannel = UNINITIALIZED; // reset local addresses and sync up RTCP ports pChannel->ccLocalRTPAddr.Addr.IP_Binary.dwAddr = 0; pChannel->ccLocalRTCPAddr.Addr.IP_Binary.dwAddr = 0; pChannel->ccLocalRTCPAddr.Addr.IP_Binary.wPort = pChannel->ccLocalRTPAddr.Addr.IP_Binary.wPort + 1; // reset remote addresses (including port numbers) pChannel->ccRemoteRTPAddr.Addr.IP_Binary.dwAddr = 0; pChannel->ccRemoteRTPAddr.Addr.IP_Binary.wPort = 0; pChannel->ccRemoteRTCPAddr.Addr.IP_Binary.dwAddr = 0; pChannel->ccRemoteRTCPAddr.Addr.IP_Binary.wPort = 0; // initialize caps memset(&pChannel->ccTermCaps,0,sizeof(CC_TERMCAP)); // initialize other info pChannel->bPayloadType = (BYTE)UNINITIALIZED; pChannel->bSessionID = (BYTE)UNINITIALIZED; // initialize direction pChannel->fInbound = FALSE; // success return TRUE; } BOOL H323AllocChannel( PH323_CHANNEL * ppChannel ) /*++ Routine Description: Allocates new channel object. Arguments: ppChannel - Pointer to DWORD-sized value in which service provider must place the newly allocated channel object. Return Values: Returns true if successful. --*/ { PH323_CHANNEL pChannel = NULL; // allocate channel object pChannel = H323HeapAlloc(sizeof(H323_CHANNEL)); // validate pointer if (pChannel == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate channel object.\n" )); // failure return FALSE; } H323DBG(( DEBUG_LEVEL_VERBOSE, "channel 0x%08lx allocated.\n", pChannel )); // reset channel object H323ResetChannel(pChannel); // transfer pointer *ppChannel = pChannel; // success return TRUE; } BOOL H323FreeChannel( PH323_CHANNEL pChannel ) /*++ Routine Description: Release memory associated with channel. Arguments: pChannel - Pointer to channel to release. Return Values: Returns true if successful. --*/ { // release memory H323HeapFree(pChannel); H323DBG(( DEBUG_LEVEL_VERBOSE, "channel 0x%08lx released.\n", pChannel )); // success return TRUE; } /////////////////////////////////////////////////////////////////////////////// // // // Public procedures // // // /////////////////////////////////////////////////////////////////////////////// BOOL H323OpenChannel( PH323_CHANNEL pChannel ) /*++ Routine Description: Opens channel to destination address. Arguments: pChannel - Pointer to channel to open. Return Values: Returns true if successful. --*/ { HRESULT hr; // open channel hr = CC_OpenChannel( pChannel->pCall->hccConf, // hConference &pChannel->hccChannel, // phChannel pChannel->bSessionID, // bSessionID 0, // bAssociatedSessionID TRUE, // bSilenceSuppression &pChannel->ccTermCaps, // pTermCap &pChannel->ccLocalRTCPAddr, // pLocalRTCPAddr 0, // bDynamicRTPPayloadType 0, // dwChannelBitRate PtrToUlong(pChannel->pCall->hdCall) // dwUserToken ); // validate if (hr != CC_OK) { H323DBG(( DEBUG_LEVEL_ERROR, "error %s (0x%08lx) opening channel 0x%08lx.\n", H323StatusToString((DWORD)hr), hr, pChannel )); // failure return FALSE; } // change channel state to opening pChannel->nState = H323_CHANNELSTATE_OPENING; H323DBG(( DEBUG_LEVEL_VERBOSE, "channel 0x%08lx opening.\n", pChannel )); // success return TRUE; } BOOL H323CloseChannel( PH323_CHANNEL pChannel ) /*++ Routine Description: Closes channel. Arguments: pChannel - Pointer to channel to close. Return Values: Returns true if successful. --*/ { HRESULT hr; // see if channel opened if (H323IsChannelOpen(pChannel) && H323IsCallActive(pChannel->pCall)) { // give peer close channel indication hr = CC_CloseChannel(pChannel->hccChannel); // validate status if (hr != CC_OK) { H323DBG(( DEBUG_LEVEL_ERROR, "error %s (0x%08lx) closing channel 0x%08lx.\n", H323StatusToString((DWORD)hr), hr, pChannel )); // // Could not close channel so just // mark as closed and continue... // } } // mark entry as allocated H323FreeChannelFromTable(pChannel,pChannel->pCall->pChannelTable); H323DBG(( DEBUG_LEVEL_VERBOSE, "channel 0x%08lx closed.\n", pChannel )); // success return TRUE; } BOOL H323AllocChannelTable( PH323_CHANNEL_TABLE * ppChannelTable ) /*++ Routine Description: Allocates table of channel objects. Arguments: ppChannelTable - Pointer to DWORD-sized value which service provider must fill in with newly allocated table. Return Values: Returns true if successful. --*/ { PH323_CHANNEL_TABLE pChannelTable; // allocate table from heap pChannelTable = H323HeapAlloc( sizeof(H323_CHANNEL_TABLE) + sizeof(PH323_CHANNEL) * H323_DEFMEDIAPERCALL ); // validate table pointer if (pChannelTable == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not allocate channel table.\n" )); // failure return FALSE; } // initialize number of entries in table pChannelTable->dwNumSlots = H323_DEFMEDIAPERCALL; // transfer pointer to caller *ppChannelTable = pChannelTable; // success return TRUE; } BOOL H323FreeChannelTable( PH323_CHANNEL_TABLE pChannelTable ) /*++ Routine Description: Deallocates table of channel objects. Arguments: pChannelTable - Pointer to channel table to release. Return Values: Returns true if successful. --*/ { DWORD i; // loop through each object in table for (i = 0; i < pChannelTable->dwNumSlots; i++) { // validate object has been allocated if (H323IsChannelAllocated(pChannelTable->pChannels[i])) { // release memory for object H323FreeChannel(pChannelTable->pChannels[i]); } } // release memory for table H323HeapFree(pChannelTable); // success return TRUE; } BOOL H323CloseChannelTable( PH323_CHANNEL_TABLE pChannelTable ) /*++ Routine Description: Closes table of channel objects. Arguments: pChannelTable - Pointer to channel table to close. Return Values: Returns true if successful. --*/ { DWORD i; // loop through each object in table for (i = 0; i < pChannelTable->dwNumSlots; i++) { // validate object is in use if (H323IsChannelInUse(pChannelTable->pChannels[i])) { // close channel object H323CloseChannel(pChannelTable->pChannels[i]); } } // success return TRUE; } BOOL H323AllocChannelFromTable( PH323_CHANNEL * ppChannel, PH323_CHANNEL_TABLE * ppChannelTable, PH323_CALL pCall ) /*++ Routine Description: Allocates channel object in table. Arguments: ppChannel - Specifies a pointer to a DWORD-sized value in which the service provider must write the allocated channel object. ppChannelTable - Pointer to pointer to channel table in which to allocate channel from (expands table if necessary). pCall - Pointer to containing call object. Return Values: Returns true if successful. --*/ { DWORD i; PH323_CHANNEL pChannel = NULL; PH323_CHANNEL_TABLE pChannelTable = *ppChannelTable; // retrieve index to next entry i = pChannelTable->dwNextAvailable; // see if previously allocated entries available if (pChannelTable->dwNumAllocated > pChannelTable->dwNumInUse) { // search table looking for available entry while (H323IsChannelInUse(pChannelTable->pChannels[i]) || !H323IsChannelAllocated(pChannelTable->pChannels[i])) { // increment index and adjust to wrap i = H323GetNextIndex(i, pChannelTable->dwNumSlots); } // retrieve pointer to object pChannel = pChannelTable->pChannels[i]; // mark entry as being in use pChannel->nState = H323_CHANNELSTATE_CLOSED; // re-initialize rtp address pChannel->ccLocalRTPAddr.Addr.IP_Binary.dwAddr = H323IsCallInbound(pCall) ? pCall->ccCalleeAddr.Addr.IP_Binary.dwAddr : pCall->ccCallerAddr.Addr.IP_Binary.dwAddr ; // re-initialize rtcp address pChannel->ccLocalRTCPAddr.Addr.IP_Binary.dwAddr = pChannel->ccLocalRTPAddr.Addr.IP_Binary.dwAddr; // increment number in use pChannelTable->dwNumInUse++; // adjust next available index pChannelTable->dwNextAvailable = H323GetNextIndex(i, pChannelTable->dwNumSlots); // transfer pointer *ppChannel = pChannel; // success return TRUE; } // see if table is full and more slots need to be allocated if (pChannelTable->dwNumAllocated == pChannelTable->dwNumSlots) { // attempt to double table pChannelTable = H323HeapReAlloc( pChannelTable, sizeof(H323_CHANNEL_TABLE) + pChannelTable->dwNumSlots * 2 * sizeof(PH323_CHANNEL) ); // validate pointer if (pChannelTable == NULL) { H323DBG(( DEBUG_LEVEL_ERROR, "could not expand channel table.\n" )); // failure return FALSE; } // adjust index into table i = pChannelTable->dwNumSlots; // adjust number of slots pChannelTable->dwNumSlots *= 2; // transfer pointer to caller *ppChannelTable = pChannelTable; } // allocate new object if (!H323AllocChannel(&pChannel)) { // failure return FALSE; } // search table looking for slot with no object allocated while (H323IsChannelAllocated(pChannelTable->pChannels[i])) { // increment index and adjust to wrap i = H323GetNextIndex(i, pChannelTable->dwNumSlots); } // store pointer to object pChannelTable->pChannels[i] = pChannel; // mark entry as being in use pChannel->nState = H323_CHANNELSTATE_CLOSED; // initialize rtp address pChannel->ccLocalRTPAddr.nAddrType = CC_IP_BINARY; pChannel->ccLocalRTPAddr.Addr.IP_Binary.dwAddr = H323IsCallInbound(pCall) ? pCall->ccCalleeAddr.Addr.IP_Binary.dwAddr : pCall->ccCallerAddr.Addr.IP_Binary.dwAddr ; pChannel->ccLocalRTPAddr.Addr.IP_Binary.wPort = LOWORD(pCall->pLine->dwNextPort++); pChannel->ccLocalRTPAddr.bMulticast = FALSE; // initialize rtcp address pChannel->ccLocalRTCPAddr.nAddrType = CC_IP_BINARY; pChannel->ccLocalRTCPAddr.Addr.IP_Binary.dwAddr = pChannel->ccLocalRTPAddr.Addr.IP_Binary.dwAddr; pChannel->ccLocalRTCPAddr.Addr.IP_Binary.wPort = LOWORD(pCall->pLine->dwNextPort++); pChannel->ccLocalRTCPAddr.bMulticast = FALSE; // increment number in use pChannelTable->dwNumInUse++; // increment number allocated pChannelTable->dwNumAllocated++; // adjust next available index pChannelTable->dwNextAvailable = H323GetNextIndex(i, pChannelTable->dwNumSlots); #if DBG { DWORD dwIPAddr; dwIPAddr = htonl(pChannel->ccLocalRTPAddr.Addr.IP_Binary.dwAddr); H323DBG(( DEBUG_LEVEL_VERBOSE, "channel 0x%08lx stored in slot %d (%s:%d).\n", pChannel, i, H323AddrToString(dwIPAddr), pChannel->ccLocalRTPAddr.Addr.IP_Binary.wPort )); } #endif // transfer pointer *ppChannel = pChannel; // success return TRUE; } BOOL H323FreeChannelFromTable( PH323_CHANNEL pChannel, PH323_CHANNEL_TABLE pChannelTable ) /*++ Routine Description: Deallocates channel object in table. Arguments: pChannel - Pointer to object to deallocate. pChannelTable - Pointer to table containing object. Return Values: Returns true if successful. --*/ { // reset channel object H323ResetChannel(pChannel); // decrement entries in use pChannelTable->dwNumInUse--; // success return TRUE; } BOOL H323LookupChannelByHandle( PH323_CHANNEL * ppChannel, PH323_CHANNEL_TABLE pChannelTable, CC_HCHANNEL hccChannel ) /*++ Routine Description: Looks up channel based on handle returned from call control module. Arguments: ppChannel - Specifies a pointer to a DWORD-sized value in which the service provider must write the channel associated with the call control handle specified. pChannelTable - Pointer to channel table to search. hccChannel - Handle return by call control module. Return Values: Returns true if successful. --*/ { DWORD i; // loop through each channel in table for (i = 0; i < pChannelTable->dwNumSlots; i++) { // see if channel handle matches the one specified if (H323IsChannelEqual(pChannelTable->pChannels[i],hccChannel)) { // tranfer channel pointer to caller *ppChannel = pChannelTable->pChannels[i]; // success return TRUE; } } // failure return FALSE; } BOOL H323LookupChannelBySessionID( PH323_CHANNEL * ppChannel, PH323_CHANNEL_TABLE pChannelTable, BYTE bSessionID ) /*++ Routine Description: Looks up channel based on session ID negotiated. Arguments: ppChannel - Specifies a pointer to a DWORD-sized value in which the service provider must write the channel associated with the call control handle specified. pChannelTable - Pointer to channel table to search. bSessionID - session id. Return Values: Returns true if successful. --*/ { DWORD i; // loop through each channel in table for (i = 0; i < pChannelTable->dwNumSlots; i++) { // see if channel handle matches the one specified if (H323IsSessionIDEqual(pChannelTable->pChannels[i],bSessionID)) { // tranfer channel pointer to caller *ppChannel = pChannelTable->pChannels[i]; // success return TRUE; } } // failure return FALSE; } BOOL H323AreThereOutgoingChannels( PH323_CHANNEL_TABLE pChannelTable, BOOL fIgnoreOpenChannels ) /*++ Routine Description: Searchs for outgoing channel objects. Arguments: pChannelTable - Pointer to channel table to search. fIgnoreOpenChannels - Restricts search to unopened channels. Return Values: Returns true if successful. --*/ { DWORD i; BOOL fFoundOk = FALSE; // loop through each channel in table for (i = 0; i < pChannelTable->dwNumSlots; i++) { // see if channel is in use and outbound if (H323IsChannelInUse(pChannelTable->pChannels[i]) && !H323IsChannelInbound(pChannelTable->pChannels[i]) && (!H323IsChannelOpen(pChannelTable->pChannels[i]) || !fIgnoreOpenChannels)) { // success return TRUE; } } // failure return FALSE; }