windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/h323/h323cc.cpp
2020-09-26 16:20:57 +08:00

1162 lines
26 KiB
C++

// 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);
}
}