|
|
// File: h323cc.cpp
#include "precomp.h"
#include "confreg.h"
#include "version.h"
EXTERN_C HINSTANCE g_hInst=NULL; // global module instance
IRTP *g_pIRTP = NULL; UINT g_capFlags = CAPFLAGS_AV_ALL;
#ifdef DEBUG
HDBGZONE ghDbgZoneCC = NULL; static PTCHAR _rgZonesCC[] = { TEXT("H323"), TEXT("Init"), TEXT("Conn"), TEXT("Channels"), TEXT("Caps"), TEXT("Member"), TEXT("unused"), TEXT("unused"), TEXT("Ref count"), TEXT("unused"), TEXT("Profile spew") };
int WINAPI CCDbgPrintf(LPTSTR lpszFormat, ... ) { va_list v1; va_start(v1, lpszFormat); DbgPrintf("H323CC", lpszFormat, v1); va_end(v1); return TRUE; } #endif /* DEBUG */
// The product ID fields are defined in the standard as an array of bytes. ASCII
// characters are used regardless of local character set.
// default Product ID and version ID strings
static char DefaultProductID[] = H323_PRODUCTNAME_STR; static char DefaultProductVersion[] = H323_PRODUCTRELEASE_STR;
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
) { switch(fdwReason) {
case DLL_PROCESS_ATTACH: DBGINIT(&ghDbgZoneCC, _rgZonesCC);
DBG_INIT_MEMORY_TRACKING(hinstDLL);
DisableThreadLibraryCalls(hinstDLL); g_hInst = hinstDLL; break;
case DLL_PROCESS_DETACH: DBG_CHECK_MEMORY_TRACKING(hinstDLL);
DBGDEINIT(&ghDbgZoneCC); break;
default: break;
}
return TRUE; }
HRESULT WINAPI CreateH323CC(IH323CallControl ** ppCC, BOOL fForCalling, UINT capFlags) { if(!ppCC) return H323CC_E_INVALID_PARAM;
DBG_SAVE_FILE_LINE *ppCC = new CH323CallControl(fForCalling, capFlags); if(!(*ppCC)) return H323CC_E_CREATE_FAILURE;
return hrSuccess; }
BOOL CH323CallControl::m_fGKProhibit = FALSE; RASNOTIFYPROC CH323CallControl::m_pRasNotifyProc = NULL;
CH323CallControl::CH323CallControl(BOOL fForCalling, UINT capFlags) : m_uRef(1), m_fForCalling(fForCalling), m_numlines(0), m_pProcNotifyConnect(NULL), m_pCapabilityResolver(NULL), m_pListenLine(NULL), m_pLineList(NULL), m_pNextToAccept(NULL), m_pUserName(NULL), m_pLocalAliases(NULL), m_pRegistrationAliases(NULL), hrLast(hrSuccess), m_pSendAudioChannel(NULL), m_pSendVideoChannel(NULL), m_uMaximumBandwidth(0) { //
// Set up caps.
//
if (fForCalling) { g_capFlags = capFlags; }
m_VendorInfo.bCountryCode = USA_H221_COUNTRY_CODE; m_VendorInfo.bExtension = USA_H221_COUNTRY_EXTENSION; m_VendorInfo.wManufacturerCode = MICROSOFT_H_221_MFG_CODE;
m_VendorInfo.pProductNumber = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING) + sizeof(DefaultProductID)); if(m_VendorInfo.pProductNumber) { m_VendorInfo.pProductNumber->wOctetStringLength = sizeof(DefaultProductID); m_VendorInfo.pProductNumber->pOctetString = ((BYTE *)m_VendorInfo.pProductNumber + sizeof(CC_OCTETSTRING)); memcpy(m_VendorInfo.pProductNumber->pOctetString, DefaultProductID, sizeof(DefaultProductID)); } m_VendorInfo.pVersionNumber = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING) + sizeof(DefaultProductVersion)); if(m_VendorInfo.pVersionNumber) { m_VendorInfo.pVersionNumber->wOctetStringLength = sizeof(DefaultProductVersion); m_VendorInfo.pVersionNumber->pOctetString = ((BYTE *)m_VendorInfo.pVersionNumber + sizeof(CC_OCTETSTRING)); memcpy(m_VendorInfo.pVersionNumber->pOctetString, DefaultProductVersion, sizeof(DefaultProductVersion)); }
RegEntry reCC(szRegInternetPhone TEXT("\\") szRegInternetPhoneNac, HKEY_LOCAL_MACHINE, FALSE, KEY_READ);
UINT uAPD = reCC.GetNumberIniStyle(TEXT ("AudioPacketDurationMs"), 0); if (uAPD) { g_AudioPacketDurationMs = uAPD; g_fRegAudioPacketDuration = TRUE; }
DBG_SAVE_FILE_LINE m_pCapabilityResolver = new CapsCtl(); if (!m_pCapabilityResolver) { ERRORMESSAGE(("CH323CallControl::CH323CallControl:cannot create capability resolver\r\n")); hrLast = H323CC_E_INIT_FAILURE; }
if(!m_pCapabilityResolver->Init()) { ERRORMESSAGE(("CH323CallControl::CH323CallControl cannot init capability resolver\r\n")); hrLast = H323CC_E_INIT_FAILURE; } }
HRESULT CH323CallControl::Initialize(PORT *lpPort) { FX_ENTRY("CH323CallControl::Initialize");
OBJ_CPT_RESET; ASSERT(m_fForCalling);
if(!HR_SUCCEEDED(LastHR())) { goto EXIT; } if(!lpPort) { SetLastHR(H323CC_E_INVALID_PARAM); goto EXIT; }
if(!Init()) { goto EXIT; } else { ASSERT(m_pListenLine); hrLast = m_pListenLine->GetLocalPort(lpPort); }
if (g_capFlags & CAPFLAGS_AV_STREAMS) { SetLastHR( ::CoCreateInstance(CLSID_RTP, NULL, CLSCTX_INPROC_SERVER, IID_IRTP, (void**)&g_pIRTP) ); } SHOW_OBJ_ETIME("CH323CallControl::Initialize"); EXIT: return LastHR(); }
HRESULT CH323CallControl::SetMaxPPBandwidth(UINT Bandwidth) { HRESULT hr = hrSuccess; LPAPPVIDCAPPIF lpIVidAppCap = NULL; DWORD dwcFormats = 0; DWORD dwcFormatsReturned = 0; DWORD x; BASIC_VIDCAP_INFO *pvidcaps = NULL; m_uMaximumBandwidth =Bandwidth;
if (g_capFlags & CAPFLAGS_AV_STREAMS) { //Set the bandwidth on every video format
hr = QueryInterface(IID_IAppVidCap, (void **)&lpIVidAppCap); if (! HR_SUCCEEDED (hr)) goto EXIT;
// Get the number of BASIC_VIDCAP_INFO structures available
hr = lpIVidAppCap->GetNumFormats((UINT*)&dwcFormats); if (! HR_SUCCEEDED (hr)) goto EXIT;
if (dwcFormats > 0) { // Allocate some memory to hold the list in
if (!(pvidcaps = (BASIC_VIDCAP_INFO*)MemAlloc(dwcFormats * sizeof (BASIC_VIDCAP_INFO)))) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto EXIT; } // Get the list
hr=lpIVidAppCap->EnumFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO), (UINT*)&dwcFormatsReturned); if (! HR_SUCCEEDED (hr)) goto EXIT;
//Set the bandwidth on each format
for (x=0;x<dwcFormatsReturned;x++) { pvidcaps[x].uMaxBitrate=m_uMaximumBandwidth; }
// Ok, now submit this list
hr = lpIVidAppCap->ApplyAppFormatPrefs(pvidcaps, dwcFormats); if (! HR_SUCCEEDED (hr)) goto EXIT; } }
//Initialize the default H.323 simcaps.
hr = m_pCapabilityResolver->ComputeCapabilitySets(m_uMaximumBandwidth); //if(!HR_SUCCEEDED(hr))
// goto EXIT;
EXIT: // let the interface go
if (lpIVidAppCap) { lpIVidAppCap->Release(); // (going out of scope) lpIVidAppCap = NULL;
} if(pvidcaps) { // Free the memory, we're done
MemFree(pvidcaps); } return hr; }
BOOL CH323CallControl::Init() { HRESULT hResult; DEBUGMSG(ZONE_INIT,("Init: this:0x%08lX\r\n", this)); SetLastHR(hrSuccess);
if (m_fForCalling) { //
// Only call control code should init CC_ stuff. Codec manipulation
// via audiocpl should not.
//
hResult = CC_Initialize(); if(!HR_SUCCEEDED(hResult)) { goto CLEANUP; } }
ASSERT(m_pCapabilityResolver); // Initialize capability data using default number, but clear the saved
// bandwidth number afterwards. This detects attempts to place or
// accept calls before the application initializes the real bandwidth
hResult = SetMaxPPBandwidth(DEF_AP_BWMAX); m_uMaximumBandwidth = 0; if(!HR_SUCCEEDED(hResult)) { goto CLEANUP; }
// Create dual connection objects for listening for new connections
if (m_fForCalling) { hResult = CreateConnection(&m_pListenLine,PID_H323); if(!HR_SUCCEEDED(hResult)) { goto CLEANUP; } if(!m_pListenLine) { hResult = H323CC_E_INIT_FAILURE; goto CLEANUP; } if(!(m_pListenLine->ListenOn(H323_PORT))) { hResult = H323CC_E_NETWORK_ERROR; goto CLEANUP; } } return TRUE;
CLEANUP: if (m_pListenLine) { m_pListenLine->Release(); m_pListenLine = NULL; } SetLastHR(hResult); return FALSE; }
CH323CallControl::~CH323CallControl() { if(m_VendorInfo.pProductNumber) MemFree(m_VendorInfo.pProductNumber); if(m_VendorInfo.pVersionNumber) MemFree(m_VendorInfo.pVersionNumber); if(m_pUserName) MemFree(m_pUserName); if(m_pLocalAliases) FreeTranslatedAliasList(m_pLocalAliases); if(m_pRegistrationAliases) FreeTranslatedAliasList(m_pRegistrationAliases);
if (m_pCapabilityResolver) { m_pCapabilityResolver->Release(); m_pCapabilityResolver = NULL; }
if (m_pSendAudioChannel) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); m_pSendAudioChannel->Release(); m_pSendAudioChannel = NULL; }
if (m_pSendVideoChannel) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); m_pSendVideoChannel->Release(); m_pSendVideoChannel = NULL; }
if (m_fForCalling) { // toast backward references to this in all
// connection objects
CConnection *pLine = m_pLineList; CConnection *pNext; while(pLine) { pNext = pLine->next; pLine->DeInit(); pLine = pNext; }
// release the listening object if it exists
if(m_pListenLine) m_pListenLine->Release();
// shutdown CALLCONT.DLL
CC_Shutdown();
if (g_pIRTP) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); g_pIRTP->Release(); g_pIRTP = NULL; }
// Put capflags back
g_capFlags = CAPFLAGS_AV_ALL; } else { ASSERT(!m_pLineList); ASSERT(!m_pListenLine); } }
ULONG CH323CallControl::AddRef() { m_uRef++; return m_uRef; }
ULONG CH323CallControl::Release() { m_uRef--; if(m_uRef == 0) { delete this; return 0; } return m_uRef; }
HRESULT CH323CallControl::SetUserDisplayName(LPWSTR lpwName) { LPWSTR lpwD; ULONG ulSize; if(!lpwName) { return (MakeResult(H323CC_E_INVALID_PARAM)); } if(lpwName) { ulSize = ((lstrlenW(lpwName) +1)*sizeof(WCHAR)); lpwD = (LPWSTR)MemAlloc(ulSize); if(!lpwD) return H323CC_E_INSUFFICIENT_MEMORY; if(m_pUserName) { MemFree(m_pUserName); } m_pUserName = lpwD; memcpy(m_pUserName, lpwName, ulSize); } return (MakeResult(hrSuccess)); }
// Find the most suitable alias for display. Return the first H323ID if it exists,
// else return the first E.164 address
PCC_ALIASITEM CH323CallControl::GetUserDisplayAlias() { WORD wC; PCC_ALIASITEM pItem, pFoundItem = NULL; if(m_pLocalAliases) { wC = m_pLocalAliases->wCount; pItem = m_pLocalAliases->pItems; while (wC--) { if(!pItem) { continue; } if(pItem->wType == CC_ALIAS_H323_ID) { if(!pItem->wDataLength || !pItem->pData) { continue; } else { pFoundItem = pItem; // done, done, done
break; // I said done
} } else if(pItem->wType == CC_ALIAS_H323_PHONE) { if(!pItem->wDataLength || !pItem->pData) { continue; } else { if(!pFoundItem) // if nothing at all was found so far
pFoundItem = pItem; // remember this
} } pItem++; } } return pFoundItem; }
CREQ_RESPONSETYPE CH323CallControl::ConnectionRequest(CConnection *pConnection) { CREQ_RESPONSETYPE Response; // decide what to do internally
// LOOKLOOK hardcoded acceptance
Response = CRR_ACCEPT; return Response; } CREQ_RESPONSETYPE CH323CallControl::FilterConnectionRequest(CConnection *pConnection, P_APP_CALL_SETUP_DATA pAppData) { CREQ_RESPONSETYPE Response = CRR_ASYNC; ASSERT(m_uMaximumBandwidth); // run it past the notification callback (if there is one)
if(m_pProcNotifyConnect) { // pass ptr to IConnection
Response = (m_pProcNotifyConnect)((IH323Endpoint *)&pConnection->m_ImpConnection, pAppData); if(Response != CRR_ACCEPT) { return Response; } } return Response; }
HRESULT CH323CallControl::RegisterConnectionNotify(CNOTIFYPROC pConnectRequestHandler) {
// reject if there's an existing registration
if (m_pProcNotifyConnect || (!pConnectRequestHandler)) { return H323CC_E_INVALID_PARAM; } m_pProcNotifyConnect = pConnectRequestHandler; return hrSuccess; }
HRESULT CH323CallControl::DeregisterConnectionNotify(CNOTIFYPROC pConnectRequestHandler) { // reject if there's not an existing registration
if (!m_pProcNotifyConnect) return H323CC_E_INVALID_PARAM; if (pConnectRequestHandler == m_pProcNotifyConnect) { m_pProcNotifyConnect = NULL; } else { return H323CC_E_INVALID_PARAM; } return hrSuccess; }
HRESULT CH323CallControl::GetNumConnections(ULONG *lp) { ULONG ulRet = m_numlines; // hide the "listening" connection object from the client/ui/whatever
if(ulRet && m_pListenLine) ulRet--; if(lp) { *lp = ulRet; } return hrSuccess; }
HRESULT CH323CallControl::GetConnobjArray(CConnection **lplpArray, UINT uSize) { UINT uPublicConnections; // # of visible objects
if(!lplpArray) return H323CC_E_INVALID_PARAM;
uPublicConnections = m_numlines; if(m_pListenLine) uPublicConnections--; if(uSize < (sizeof(CConnection **) * uPublicConnections)) { return H323CC_E_MORE_CONNECTIONS; } CConnection *pLine = m_pLineList; CConnection *pNext; int i=0; while(pLine) { DEBUGCHK(uSize--); pNext = pLine->next; // return everything but the objects used for listening
if(pLine != m_pListenLine) { lplpArray[i++] = pLine; } pLine = pNext; } return hrSuccess; };
HRESULT CH323CallControl::GetConnectionArray(IH323Endpoint * *lplpArray, UINT uSize) {
UINT uPublicConnections; // # of visible objects
if(!lplpArray) return H323CC_E_INVALID_PARAM;
uPublicConnections = m_numlines; if(m_pListenLine) uPublicConnections--;
if(uSize < (sizeof(IH323Endpoint * *) * uPublicConnections)) { return H323CC_E_MORE_CONNECTIONS; } CConnection *pLine = m_pLineList; CConnection *pNext; int i=0; while(pLine) { DEBUGCHK(uSize--); pNext = pLine->next; // return everything but the objects used for listening
if(pLine != m_pListenLine) { lplpArray[i++] = (IH323Endpoint *)&pLine->m_ImpConnection; } pLine = pNext; } return hrSuccess; };
//
// protocol specific CreateConnection
//
HRESULT CH323CallControl::CreateConnection(CConnection **lplpConnection, GUID PIDofProtocolType) { SetLastHR(hrSuccess); CConnection *lpConnection, *lpList; if(!lplpConnection) { SetLastHR(MakeResult(H323CC_E_INVALID_PARAM)); goto EXIT; } *lplpConnection = NULL; DBG_SAVE_FILE_LINE if(!(lpConnection = new CConnection)) { SetLastHR(MakeResult(H323CC_E_INSUFFICIENT_MEMORY)); goto EXIT; }
hrLast = lpConnection->Init(this, PIDofProtocolType);
// LOOKLOOK need to insert this connection in the connection list
if(!HR_SUCCEEDED(hrSuccess)) { delete lpConnection; lpConnection = NULL; } else { *lplpConnection = lpConnection; // insert in connection list
lpList = m_pLineList; m_pLineList = lpConnection; lpConnection->next =lpList; m_numlines++; } EXIT: return (LastHR());
}
//
// IH323CallControl->CreateConnection(), EXTERNAL create connection interface.
//
HRESULT CH323CallControl::CreateConnection(IH323Endpoint * *lplpLine, GUID PIDofProtocolType) { SetLastHR(hrSuccess); CConnection *lpConnection; ASSERT(m_uMaximumBandwidth); if(!m_uMaximumBandwidth) { SetLastHR(MakeResult(H323CC_E_NOT_INITIALIZED)); goto EXIT; } if(!lplpLine) { SetLastHR(MakeResult(H323CC_E_INVALID_PARAM)); goto EXIT; } *lplpLine = NULL; hrLast = CreateConnection(&lpConnection, PIDofProtocolType); if(HR_SUCCEEDED(LastHR()) && lpConnection) { *lplpLine = (IH323Endpoint *)&lpConnection->m_ImpConnection; } EXIT: return (LastHR()); }
//
// CreateLocalCommChannel creates the send side of a media channel outside the context
// of any call.
//
HRESULT CH323CallControl::CreateLocalCommChannel(ICommChannel** ppCommChan, LPGUID lpMID, IMediaChannel* pMediaStream) {
if(!ppCommChan || !lpMID || !pMediaStream) return H323CC_E_INVALID_PARAM; if (*lpMID == MEDIA_TYPE_H323AUDIO) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
// allow only one of each media type to be created. This is an artificial
// limitation.
if(m_pSendAudioChannel) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; }
DBG_SAVE_FILE_LINE if(!(m_pSendAudioChannel = new ImpICommChan)) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; } hrLast = m_pSendAudioChannel->StandbyInit(lpMID, m_pCapabilityResolver, pMediaStream); if(!HR_SUCCEEDED(hrLast)) { m_pSendAudioChannel->Release(); m_pSendAudioChannel = NULL; goto EXIT; } hrLast = m_pSendAudioChannel->QueryInterface(IID_ICommChannel, (void **)ppCommChan); if(!HR_SUCCEEDED(hrLast)) { m_pSendAudioChannel->Release(); m_pSendAudioChannel = NULL; goto EXIT; } } else if (*lpMID == MEDIA_TYPE_H323VIDEO) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
// allow only one of each media type to be created. This is an artificial
// limitation.
if(m_pSendVideoChannel) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; }
DBG_SAVE_FILE_LINE if(!(m_pSendVideoChannel = new ImpICommChan)) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; } hrLast = m_pSendVideoChannel->StandbyInit(lpMID, m_pCapabilityResolver, pMediaStream); if(!HR_SUCCEEDED(hrLast)) { m_pSendVideoChannel->Release(); m_pSendVideoChannel = NULL; goto EXIT; } hrLast = m_pSendVideoChannel->QueryInterface(IID_ICommChannel, (void **)ppCommChan); if(!HR_SUCCEEDED(hrLast)) { m_pSendVideoChannel->Release(); m_pSendVideoChannel = NULL; goto EXIT; } } else hrLast = H323CC_E_INVALID_PARAM; EXIT: return hrLast; }
ICtrlCommChan *CH323CallControl::QueryPreviewChannel(LPGUID lpMID) { HRESULT hr; ICtrlCommChan *pCommChan = NULL; if(*lpMID == MEDIA_TYPE_H323AUDIO) { if(m_pSendAudioChannel) { hr = m_pSendAudioChannel->QueryInterface(IID_ICtrlCommChannel, (void **)&pCommChan); if(HR_SUCCEEDED(hr)) { return pCommChan; } } } else if (*lpMID == MEDIA_TYPE_H323VIDEO) { if(m_pSendVideoChannel) { hr = m_pSendVideoChannel->QueryInterface(IID_ICtrlCommChannel, (void **)&pCommChan); if(HR_SUCCEEDED(hr)) { return pCommChan; } } } // fallout to error case
return NULL; }
HRESULT CH323CallControl::RemoveConnection(CConnection *lpConnection) { SetLastHR(hrSuccess); CConnection *lpList; UINT nLines;
if((lpConnection == NULL) || lpConnection->m_pH323CallControl != this) { SetLastHR(MakeResult(H323CC_E_INVALID_PARAM)); goto EXIT; } m_numlines--; // update count NOW
// use # of lines for bug detection in list management code
nLines = m_numlines;
if(m_pListenLine == lpConnection) m_pListenLine = NULL; // zap the back pointer of the connection NOW - this is crucial for
// implementing "asynchronous delete" of connection objects
lpConnection->m_pH323CallControl = NULL;
// find it in the connection list and remove it
// sp. case head
if(m_pLineList== lpConnection) { m_pLineList = lpConnection->next; } else { lpList = m_pLineList; while(lpList->next && nLines) { if(lpList->next == lpConnection) { lpList->next = lpConnection->next; break; } lpList = lpList->next; nLines--; } }
EXIT: return (LastHR()); }
STDMETHODIMP CH323CallControl::QueryInterface( REFIID iid, void ** ppvObject) { // this breaks the rules for the official COM QueryInterface because
// the interfaces that are queried for are not necessarily real COM
// interfaces. The reflexive property of QueryInterface would be broken in
// that case.
HRESULT hr = E_NOINTERFACE; if(!ppvObject) return hr; *ppvObject = 0; if ((iid == IID_IH323CC) || (iid == IID_IUnknown))// satisfy symmetric property of QI
{ *ppvObject = this; hr = hrSuccess; AddRef(); } else if (iid == IID_IAppAudioCap ) { hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject); } else if(iid == IID_IAppVidCap ) { hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject); } else if(iid == IID_IDualPubCap ) { hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject); }
return (hr); }
//
// Create a copy of the alias names in the (somewhat bogus) format that
// CALLCONT expects. The destination format has a two-part string for every
// entry, but the lower layers concatenate the parts. Someday H323CC and CALLCONT
// will be one, and all the extraneous layers, copies of data, and redundant
// validations won't be needed.
//
HRESULT AllocTranslatedAliasList(PCC_ALIASNAMES *ppDest, P_H323ALIASLIST pSource) { HRESULT hr = H323CC_E_INVALID_PARAM; WORD w; PCC_ALIASNAMES pNewAliases = NULL; PCC_ALIASITEM pDestItem; P_H323ALIASNAME pSrcItem; if(!ppDest || !pSource || pSource->wCount == 0) { goto ERROR_OUT; } *ppDest = NULL; pNewAliases = (PCC_ALIASNAMES)MemAlloc(sizeof(CC_ALIASNAMES)); if(!pNewAliases) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto ERROR_OUT; } pNewAliases->wCount = 0; pNewAliases->pItems = (PCC_ALIASITEM)MemAlloc(pSource->wCount*sizeof(CC_ALIASITEM)); if(!pNewAliases->pItems) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto ERROR_OUT; } for(w=0;w<pSource->wCount;w++) { pDestItem = pNewAliases->pItems+w; pSrcItem = pSource->pItems+w; // don't tolerate empty entries - error out if any exist
if(pSrcItem->wDataLength && pSrcItem->lpwData) { if(pSrcItem->aType ==AT_H323_ID) { pDestItem->wType = CC_ALIAS_H323_ID; } else if(pSrcItem->aType ==AT_H323_E164) { pDestItem->wType = CC_ALIAS_H323_PHONE; } else { // don't know how to translate this. I hope that the need for translation
// goes away before new alias types are added. Adding an alias type
// (H323_URL for example) requires many changes in lower layers anyway,
// so that would be a good time to merge H323CC and CALLCONT.
goto ERROR_OUT; // return invalid param
} pDestItem->wPrefixLength = 0; // this prefix thing is bogus
pDestItem->pPrefix = NULL; pDestItem->pData = (LPWSTR)MemAlloc(pSrcItem->wDataLength *sizeof(WCHAR)); if(pDestItem->pData == NULL) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto ERROR_OUT; } // got good data. Copy the data, set size/length, and count it
memcpy(pDestItem->pData, pSrcItem->lpwData, pSrcItem->wDataLength * sizeof(WCHAR)); pDestItem->wDataLength = pSrcItem->wDataLength; pNewAliases->wCount++; } else { goto ERROR_OUT; } } // got here, so output good data
hr = hrSuccess; *ppDest = pNewAliases; //pNewAliases = NULL; // not needed if returning here instead of falling out
return hr; ERROR_OUT: if(pNewAliases) // then it's an error condition needing cleanup
{ FreeTranslatedAliasList(pNewAliases); } return hr; } VOID FreeTranslatedAliasList(PCC_ALIASNAMES pDoomed) { WORD w; PCC_ALIASITEM pDoomedItem; if(!pDoomed) return; for(w=0;w<pDoomed->wCount;w++) { pDoomedItem = pDoomed->pItems+w; // don't tolerate empty entries - error out if any exist
if(pDoomedItem->wDataLength && pDoomedItem->pData) { MemFree(pDoomedItem->pData); } else ASSERT(0); } MemFree(pDoomed->pItems); MemFree(pDoomed); }
STDMETHODIMP CH323CallControl::SetUserAliasNames(P_H323ALIASLIST pAliases) { HRESULT hr = hrSuccess; PCC_ALIASNAMES pNewAliases = NULL; PCC_ALIASITEM pItem; hr = AllocTranslatedAliasList(&pNewAliases, pAliases); if(!HR_SUCCEEDED(hr)) return hr;
ASSERT(pNewAliases); if(m_pLocalAliases) FreeTranslatedAliasList(m_pLocalAliases); m_pLocalAliases = pNewAliases; return hr; }
STDMETHODIMP CH323CallControl::EnableGatekeeper(BOOL bEnable, PSOCKADDR_IN pGKAddr, P_H323ALIASLIST pAliases, RASNOTIFYPROC pRasNotifyProc) { HRESULT hr = hrSuccess;
PCC_ALIASNAMES pNewAliases = NULL; PCC_ALIASITEM pItem;
m_pRasNotifyProc = pRasNotifyProc; if(bEnable) { if(!pRasNotifyProc || !pGKAddr || !pAliases) { return H323CC_E_INVALID_PARAM; } if((pGKAddr->sin_addr.s_addr == INADDR_NONE) || (pGKAddr->sin_addr.s_addr == INADDR_ANY)) { return H323CC_E_INVALID_PARAM; } hr = AllocTranslatedAliasList(&pNewAliases, pAliases); if(!HR_SUCCEEDED(hr)) return hr;
ASSERT(pNewAliases); if(m_pRegistrationAliases) FreeTranslatedAliasList(m_pRegistrationAliases); m_pRegistrationAliases = pNewAliases; // reset "I can place calls" state
m_fGKProhibit = FALSE; hr = CC_EnableGKRegistration(bEnable, pGKAddr, m_pRegistrationAliases, &m_VendorInfo, 0, // no multipoint/MC funtionality
RasNotify); } else { // we are turning off knowledge of what a gatekeeper is,
// so reset "I can place calls" state.
m_fGKProhibit = FALSE; hr = CC_EnableGKRegistration(bEnable, NULL, NULL, NULL, 0, RasNotify); if(m_pRegistrationAliases) FreeTranslatedAliasList(m_pRegistrationAliases); m_pRegistrationAliases = NULL; } return hr; }
STDMETHODIMP CH323CallControl::GetGKCallPermission() { if(m_fGKProhibit) return CONN_E_GK_NOT_REGISTERED; else return hrSuccess; }
VOID CALLBACK CH323CallControl::RasNotify(DWORD dwRasEvent, HRESULT hReason) {
switch(dwRasEvent) { case RAS_REG_CONFIRM: // received RCF (registration confirmed)
// reset "I can place calls" state
m_fGKProhibit = FALSE; break; case RAS_REG_TIMEOUT: // GK did not respond
case RAS_UNREG_CONFIRM: // received UCF (unregistration confirmed)
default: // do nothing. (except pass notification upward
break; case RAS_REJECTED: // received RRJ (registration rejected)
m_fGKProhibit = TRUE; break; case RAS_UNREG_REQ: // received URQ
m_fGKProhibit = TRUE; break; } if(m_pRasNotifyProc) { (m_pRasNotifyProc)(dwRasEvent, hReason); } }
|