windows-nt/Source/XPSP1/NT/enduser/netmeeting/t120/mst120/events.cpp
2020-09-26 16:20:57 +08:00

803 lines
26 KiB
C++

#include "precomp.h"
#include "events.hpp"
#include "ernccm.hpp"
#include "erncconf.hpp"
#include "erncvrsn.hpp"
#include "nccglbl.hpp"
extern PController g_pMCSController;
GUID g_csguidSecurity = GUID_SECURITY;
CWorkItem::~CWorkItem(void) { } // pure virtual
BOOL GetSecurityInfo(ConnectionHandle connection_handle, PBYTE pInfo, PDWORD pcbInfo);
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Implementation of Methods for CInviteIndWork
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CInviteIndWork::
CInviteIndWork
(
PCONFERENCE _pConference,
LPCWSTR _wszCallerID,
PT120PRODUCTVERSION _pRequestorVersion,
GCCUserData **_ppUserData,
UINT _nUserData,
CLogicalConnection * _pConEntry
)
:
CWorkItem(_pConference),
m_pConf(_pConference),
m_pRequestorVersion(_pRequestorVersion),
m_nUserData(_nUserData),
m_fSecure(_pConEntry->IsConnectionSecure())
{
DebugEntry(CInviteIndWork::CInviteIndWork);
// If there is version information, then take a copy of it
// as this is going asynchronous.
if (m_pRequestorVersion)
{
m_RequestorVersion = *m_pRequestorVersion;
}
// Take copy of caller ID.
// Note memory allocation failure proceeds with NULL ID.
m_pwszCallerID = ::My_strdupW(_wszCallerID);
// Create the user data list for the ui
if(_nUserData)
{
DBG_SAVE_FILE_LINE
m_pUserDataList = new USERDATAINFO[_nUserData];
if (NULL != m_pUserDataList)
{
for (UINT i = 0; i < m_nUserData; i++)
{
if ((*_ppUserData)->octet_string->length < sizeof(GUID))
{
// skip this user data
i--;
m_nUserData--;
_ppUserData++;
continue;
}
m_pUserDataList[i].pGUID = (GUID*)(*_ppUserData)->octet_string->value;
m_pUserDataList[i].pData = (*_ppUserData)->octet_string->value + sizeof(GUID);
m_pUserDataList[i].cbData = (*_ppUserData)->octet_string->length - sizeof(GUID);
// Verify security data
if (0 == CompareGuid(m_pUserDataList[i].pGUID, &g_csguidSecurity)) {
// Check data against transport level
PBYTE pbData = NULL;
DWORD cbData = 0;
BOOL fTrust = FALSE;
if (m_pUserDataList[i].cbData != 0 && GetSecurityInfo(_pConEntry->GetConnectionHandle(),NULL,&cbData)) {
if (cbData) {
// We are directly connected, so verify the information
pbData = new BYTE[cbData];
if (NULL != pbData) {
GetSecurityInfo(_pConEntry->GetConnectionHandle(),pbData,&cbData);
if ( m_pUserDataList[i].cbData != cbData ||
memcmp(pbData, m_pUserDataList[i].pData,
cbData)) {
WARNING_OUT(("SECURITY MISMATCH: (%s) vs (%s)", pbData, m_pUserDataList[i].pData));
}
else {
// Verification OK
fTrust = TRUE;
}
delete pbData;
}
else {
ERROR_OUT(("Failed to alloc %d bytes for security data verification", cbData));
}
}
}
if (FALSE == fTrust) {
// Leave the security GUID in place, but NULL out the data to signal distrust.
WARNING_OUT(("CInviteIndWork: Nulling out security"));
m_pUserDataList[i].pData = NULL;
m_pUserDataList[i].cbData = 0;
}
}
_ppUserData++;
}
}
else
{
ERROR_OUT(("CInviteIndWork::CInviteIndWork: Out of memory"));
m_nUserData = 0;
}
}
else
{
m_pUserDataList = NULL;
}
DebugExitVOID(CInviteIndWork::CInviteIndWork);
}
CInviteIndWork::
~CInviteIndWork(void)
{
DebugEntry(CInviteIndWork::~CInviteIndWork);
//
// If we substituted transport security data for roster data,
// free that buffer now
//
delete m_pwszCallerID;
delete [] m_pUserDataList;
DebugExitVOID(CInviteIndWork::~CInviteIndWork);
}
void CInviteIndWork::
DoWork(void)
{
DebugEntry(CInviteIndWork::DoWork);
// Now we are actually processing the invite, validate that there
// are no other conferences of the same name, and, if not, block
// a conference of the same name by setting the conference to be active,
// and give invite request up to the UI.
PCONFERENCE pOtherConf = g_pNCConfMgr->GetConferenceFromName(m_pConf->GetName());
if (NULL == pOtherConf)
{
m_pConf->SetNotifyToDo(TRUE);
g_pCallbackInterface->OnIncomingInviteRequest((CONF_HANDLE) m_pConf,
GetCallerID(),
m_pRequestorVersion,
m_pUserDataList,
m_nUserData,
m_fSecure);
}
else
{
m_pConf->InviteResponse(UI_RC_CONFERENCE_ALREADY_EXISTS);
}
DebugExitVOID(CInviteIndWork::DoWork);
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Implementation of Methods for CJoinIndWork
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CJoinIndWork::
CJoinIndWork
(
GCCResponseTag Tag,
PCONFERENCE _pConference,
LPCWSTR _wszCallerID,
CLogicalConnection *_pConEntry,
PT120PRODUCTVERSION _pRequestorVersion,
UINT _nUserData,
GCCUserData **_ppUserData,
HRESULT *pRetCode
)
:
CWorkItem(_pConference),
m_nResponseTag(Tag),
m_pConf(_pConference),
m_pConEntry(_pConEntry),
m_pRequestorVersion(_pRequestorVersion),
m_nUserData(_nUserData),
m_pUserDataList(NULL),
m_ppUserData(NULL)
{
DebugEntry(CJoinIndWork::CJoinIndWork);
*pRetCode = NO_ERROR;
#ifdef DEBUG
SOCKET socket_number;
g_pMCSController->FindSocketNumber(m_pConEntry->GetConnectionHandle(),&socket_number);
#endif
// If there is version information, then take a copy of it
// as this is going asynchronous.
if (m_pRequestorVersion)
{
m_RequestorVersion = *m_pRequestorVersion;
}
// Take copy of caller ID because T120
// implementation is not keeping its copy valid
// until the join response.
// Note that memory allocation failure proceeds with
// NULL caller ID.
m_pwszCallerID = ::My_strdupW(_wszCallerID);
// Add the user data list for forwarded join requests and the UI.
if (m_nUserData && NULL != _ppUserData)
{
DBG_SAVE_FILE_LINE
m_pUserDataList = new USERDATAINFO[m_nUserData];
if (NULL != m_pUserDataList)
{
::ZeroMemory(m_pUserDataList, sizeof(USERDATAINFO) * m_nUserData);
DBG_SAVE_FILE_LINE
m_ppUserData = new GCCUserData * [m_nUserData];
if (NULL != m_ppUserData)
{
::ZeroMemory(m_ppUserData, sizeof(GCCUserData *) * m_nUserData);
for (UINT i = 0; i < m_nUserData; i++)
{
// Calculate the total size to allocate for this entry.
UINT cbUserDataStructSize = ROUNDTOBOUNDARY(sizeof(GCCUserData));
UINT cbNonStdIDSize = ROUNDTOBOUNDARY((* _ppUserData)->key.h221_non_standard_id.length);
UINT cbOctetStringSize = ROUNDTOBOUNDARY((* _ppUserData)->octet_string->length);
UINT cbTotalSize = cbUserDataStructSize + cbNonStdIDSize + sizeof(OSTR) + cbOctetStringSize;
// Allocate a single memory buffer
DBG_SAVE_FILE_LINE
LPBYTE pData = new BYTE[cbTotalSize];
if (NULL != pData)
{
// Set up pointers
GCCUserData *pUserData = (GCCUserData *) pData;
::ZeroMemory(pUserData, sizeof(GCCUserData));
pUserData->key.h221_non_standard_id.value = (LPBYTE) (pData + cbUserDataStructSize);
pUserData->octet_string = (LPOSTR) (pData + cbUserDataStructSize + cbNonStdIDSize);
pUserData->octet_string->value = ((LPBYTE) pUserData->octet_string) + sizeof(OSTR);
// Copy user data to prevent it from being lost when callback message is freed.
m_ppUserData[i] = pUserData;
// Copy key
pUserData->key.key_type = (* _ppUserData)->key.key_type;
ASSERT(pUserData->key.key_type == GCC_H221_NONSTANDARD_KEY);
pUserData->key.h221_non_standard_id.length = (* _ppUserData)->key.h221_non_standard_id.length;
::CopyMemory(pUserData->key.h221_non_standard_id.value,
(* _ppUserData)->key.h221_non_standard_id.value,
pUserData->key.h221_non_standard_id.length);
// Copy data
pUserData->octet_string->length = (* _ppUserData)->octet_string->length;
::CopyMemory(pUserData->octet_string->value,
(* _ppUserData)->octet_string->value,
pUserData->octet_string->length);
m_pUserDataList[i].pGUID = (GUID *)pUserData->octet_string->value;
m_pUserDataList[i].cbData = pUserData->octet_string->length - sizeof(GUID);
m_pUserDataList[i].pData = pUserData->octet_string->value + sizeof(GUID);
if (0 == CompareGuid(m_pUserDataList[i].pGUID, &g_csguidSecurity)) {
// Check data against transport level
PBYTE pbData = NULL;
DWORD cbData = 0;
BOOL fTrust = FALSE;
if (m_pUserDataList[i].cbData != 0 &&
GetSecurityInfo(m_pConEntry->GetConnectionHandle(),NULL,&cbData)) {
if (cbData == NOT_DIRECTLY_CONNECTED) {
// This means we are not directly connected,
// transitivity. so trust by
fTrust = TRUE;
}
else {
pbData = new BYTE[cbData];
if (NULL != pbData) {
GetSecurityInfo(m_pConEntry->GetConnectionHandle(),pbData,&cbData);
// Does the data match?
if (cbData != m_pUserDataList[i].cbData ||
memcmp(pbData,
m_pUserDataList[i].pData,
cbData)) {
WARNING_OUT(("SECURITY MISMATCH: (%s) vs (%s)", pbData, m_pUserDataList[i].pData));
}
else {
fTrust = TRUE;
}
delete pbData;
}
else {
ERROR_OUT(("Failed to alloc %d bytes for security data verification", cbData));
}
}
}
if (FALSE == fTrust) {
// Leave the security GUID in place, but NULL out the data to signal distrust.
m_pUserDataList[i].pData = NULL;
m_pUserDataList[i].cbData = 0;
pUserData->octet_string->length = sizeof(GUID);
}
}
_ppUserData++;
}
else
{
ERROR_OUT(("CJoinIndWork::CJoinIndWork: can't create pData, cbTotalSize=%u", cbTotalSize));
*pRetCode = UI_RC_OUT_OF_MEMORY;
}
} // for
}
else
{
ERROR_OUT(("CJoinIndWork::CJoinIndWork: can't create m_ppUserData, m_nUserData=%u", m_nUserData));
*pRetCode = UI_RC_OUT_OF_MEMORY;
}
}
else
{
ERROR_OUT(("CJoinIndWork::CJoinIndWork: can't create m_pUserDataList, m_nUserData=%u", m_nUserData));
*pRetCode = UI_RC_OUT_OF_MEMORY;
}
} // if
DebugExitVOID(CJoinIndWork::CJoinIndWork);
}
CJoinIndWork::
~CJoinIndWork(void)
{
DebugEntry(CJoinIndWork::~CJoinIndWork);
delete m_pwszCallerID;
for (UINT i = 0; i < m_nUserData; i++)
{
delete (LPBYTE) m_ppUserData[i]; // pData in the constructor
}
delete m_ppUserData;
delete m_pUserDataList;
DebugExitVOID(CJoinIndWork::~CJoinIndWork);
}
void CJoinIndWork::
DoWork(void)
{
DebugEntry(CJoinIndWork::DoWork);
// Notify the core.
g_pCallbackInterface->OnIncomingJoinRequest((CONF_HANDLE) m_pConf,
m_pwszCallerID,
m_pRequestorVersion,
m_pUserDataList,
m_nUserData);
DebugExitVOID(CJoinIndWork::DoWork);
}
HRESULT CJoinIndWork::
Respond ( GCCResult _Result )
{
DebugEntry(CJoinIndWork::Respond);
// It is a response from the core.
HRESULT hr = ::GCCJoinResponseWrapper(m_nResponseTag,
NULL,
_Result,
m_pConf->GetID(),
m_nUserData,
m_ppUserData);
DebugExitHRESULT(CJoinIndWork::Respond, hr);
return hr;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Implementation of Methods for CSequentialWorkList
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void CSequentialWorkList::
AddWorkItem ( CWorkItem *pWorkItem )
{
DebugEntry(CSequentialWorkList::AddWorkItem);
Append(pWorkItem);
// If first entry in list, then kick off handler.
if (1 == GetCount())
{
pWorkItem->DoWork();
}
DebugExitVOID(CSequentialWorkList::AddWorkItem);
}
void CSequentialWorkList::
RemoveWorkItem ( CWorkItem *pWorkItem )
{
DebugEntry(CSequentialWorkList::RemoveWorkItem);
if (pWorkItem)
{
// Make a note as to whether we are going to remove the head
// work item in the list.
BOOL bHeadItemRemoved = (pWorkItem == PeekHead());
// Remove work item from list and destroy it.
if (Remove(pWorkItem))
{
delete pWorkItem;
// If there are more entries in the list, and we removed the
// first one, then start the work of the next one in line.
// Note that before doing this, the pointer to the workitem
// was NULLed out (above) to prevent reentracy problems.
if (bHeadItemRemoved && !IsEmpty())
{
PeekHead()->DoWork();
}
}
else
{
ASSERT(! bHeadItemRemoved);
}
}
DebugExitVOID(CSequentialWorkList::RemoveWorkItem);
}
void CSequentialWorkList::
PurgeListEntriesByOwner ( DCRNCConference *pOwner )
{
CWorkItem *pWorkItem;
DebugEntry(CSequentialWorkList::PurgeListEntriesByOwner);
if (NULL != pOwner)
{
// Note that head entry is removed last to stop work being started
// on other entries in the list that are owned by pOwner.
// Check to ensure there is a head item in the list.
if (NULL != (pWorkItem = PeekHead()))
{
// Remember we are going to remove the head.
BOOL fHeadToRemove = pWorkItem->IsOwnedBy(pOwner);
// Walk remaining entries in the list removing them.
BOOL fMoreToRemove;
do
{
fMoreToRemove = FALSE;
Reset();
while (NULL != (pWorkItem = Iterate()))
{
if (pWorkItem->IsOwnedBy(pOwner))
{
Remove(pWorkItem);
delete pWorkItem;
fMoreToRemove = TRUE;
break;
}
}
}
while (fMoreToRemove);
// Now done removing all entries, including the head if needed...
if (fHeadToRemove && ! IsEmpty())
{
PeekHead()->DoWork();
}
}
}
DebugExitVOID(CSequentialWorkList::PurgeListEntriesByOwner);
}
void CSequentialWorkList::
DeleteList(void)
{
CWorkItem *pWorkItem;
while (NULL != (pWorkItem = Get()))
{
delete pWorkItem;
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Implementation of Methods for CQueryRemoteWork
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CQueryRemoteWork::
CQueryRemoteWork
(
LPVOID pCallerContext,
GCCAsymmetryType eAsymType,
LPCSTR pcszNodeAddress,
BOOL fSecure,
HRESULT *pRetCode
)
:
CWorkItem(pCallerContext),
m_hGCCConnHandle(NULL),
m_apConfNames(NULL),
m_fRemoteIsMCU(FALSE),
m_eAsymType(eAsymType),
m_pVersion(NULL),
m_fSecure(fSecure),
m_apConfDescriptors(NULL)
{
DebugEntry(CQueryRemoteWork::CQueryRemoteWork);
char szAddress[RNC_MAX_NODE_STRING_LEN];
::BuildAddressFromNodeDetails((LPSTR) pcszNodeAddress, &szAddress[0]);
m_pszAddress = ::My_strdupA(&szAddress[0]);
m_hr = (NULL != m_pszAddress) ? NO_ERROR : UI_RC_OUT_OF_MEMORY;
*pRetCode = m_hr;
DebugExitVOID(CQueryRemoteWork::CQueryRemoteWork);
}
CQueryRemoteWork::
~CQueryRemoteWork(void)
{
LPWSTR *ppTempTargetName;
LPWSTR *ppTempTargetDescriptor;
DebugEntry(CQueryRemoteWork::~CQueryRemoteWork);
// Clean up memory allocated.
if (m_apConfNames)
{
ppTempTargetName = m_apConfNames;
while (*ppTempTargetName)
{
delete *(ppTempTargetName++);
}
delete [] m_apConfNames;
}
if (m_apConfDescriptors)
{
ppTempTargetDescriptor = m_apConfDescriptors;
while (*ppTempTargetDescriptor)
{
delete *(ppTempTargetDescriptor++);
}
delete [] m_apConfDescriptors;
}
delete m_pszAddress;
DebugExitVOID(CQueryRemoteWork::~CQueryRemoteWork);
}
void CQueryRemoteWork::
DoWork(void)
{
GCCError GCCrc;
GCCNodeType nodeType;
GCCAsymmetryIndicator asymmetry_indicator;
DebugEntry(CQueryRemoteWork::DoWork);
::LoadAnnouncePresenceParameters(&nodeType, NULL, NULL, NULL);
asymmetry_indicator.asymmetry_type = m_eAsymType;
asymmetry_indicator.random_number = 0;
if (asymmetry_indicator.asymmetry_type == GCC_ASYMMETRY_UNKNOWN)
{
m_nRandSeed = (int) ::GetTickCount();
m_LocalAsymIndicator.random_number = ((GenerateRand() << 16) + GenerateRand());
asymmetry_indicator.random_number = m_LocalAsymIndicator.random_number;
m_LocalAsymIndicator.asymmetry_type = GCC_ASYMMETRY_UNKNOWN;
m_fInUnknownQueryRequest = TRUE;
}
GCCrc = g_pIT120ControlSap->ConfQueryRequest(
nodeType,
&asymmetry_indicator,
NULL,
(TransportAddress) m_pszAddress,
m_fSecure,
g_nVersionRecords,
g_ppVersionUserData,
&m_hGCCConnHandle);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfQueryRequest, rc=%d", GCCrc));
if (NO_ERROR != (m_hr = ::GetGCCRCDetails(GCCrc)))
{
AsyncQueryRemoteResult();
}
DebugExitHRESULT(CQueryRemoteWork::DoWork, m_hr);
}
void CQueryRemoteWork::
HandleQueryConfirmation ( QueryConfirmMessage * pQueryMessage )
{
UINT NumberOfConferences;
GCCConferenceDescriptor ** ppConferenceDescriptor;
PWSTR * ppTempTargetName;
PWSTR ConferenceTextName;
GCCConferenceName * pGCCConferenceName;
PWSTR * ppTempTargetDescriptor;
PWSTR pwszConfDescriptor=NULL;
HRESULT hrTmp;
DebugEntry(CQueryRemoteWork::HandleQueryConfirmation);
// If no error, then package up information.
m_hr = ::GetGCCResultDetails(pQueryMessage->result);
if (NO_ERROR == m_hr)
{
m_fRemoteIsMCU = (pQueryMessage->node_type == GCC_MCU);
NumberOfConferences = pQueryMessage->number_of_descriptors;
DBG_SAVE_FILE_LINE
m_apConfNames = new PWSTR[NumberOfConferences + 1];
m_apConfDescriptors = new PWSTR[NumberOfConferences + 1];
if (!m_apConfNames || !m_apConfDescriptors)
{
m_hr = UI_RC_OUT_OF_MEMORY;
}
else
{
ppConferenceDescriptor = pQueryMessage->conference_descriptor_list;
ppTempTargetName = m_apConfNames;
ppTempTargetDescriptor = m_apConfDescriptors;
while (NumberOfConferences--)
{
pwszConfDescriptor = (*(ppConferenceDescriptor))->conference_descriptor;
pGCCConferenceName = &(*(ppConferenceDescriptor++))->conference_name;
if (pwszConfDescriptor != NULL)
{
pwszConfDescriptor = ::My_strdupW(pwszConfDescriptor);
}
ConferenceTextName = pGCCConferenceName->text_string;
if (ConferenceTextName != NULL)
{
ConferenceTextName = ::My_strdupW(ConferenceTextName);
if (!ConferenceTextName)
{
// Out of memory, give back what we have.
m_hr = UI_RC_OUT_OF_MEMORY;
break;
}
}
else
if (pGCCConferenceName->numeric_string != NULL)
{
ConferenceTextName = ::AnsiToUnicode((PCSTR)pGCCConferenceName->numeric_string);
if (!ConferenceTextName)
{
// Out of memory, give back what we have.
m_hr = UI_RC_OUT_OF_MEMORY;
break;
}
}
if (ConferenceTextName)
{
*(ppTempTargetName++) = ConferenceTextName;
*(ppTempTargetDescriptor++) = pwszConfDescriptor;
}
}
*ppTempTargetName = NULL;
*ppTempTargetDescriptor = NULL;
}
}
// Copy version information out of message.
m_pVersion = ::GetVersionData(pQueryMessage->number_of_user_data_members,
pQueryMessage->user_data_list);
if (m_pVersion)
{
m_Version = *m_pVersion;
m_pVersion = &m_Version;
}
m_fInUnknownQueryRequest = FALSE;
hrTmp = m_hr;
// Propagate the result directly without posting a message.
SyncQueryRemoteResult();
DebugExitHRESULT(CQueryRemoteWork::HandleQueryConfirmation, hrTmp);
}
void CQueryRemoteWork::
SyncQueryRemoteResult(void)
{
DebugEntry(CQueryRemoteWork::SyncQueryRemoteResult);
// Let the user know the result of his request.
// The user is expected to call Release() after getting the result,
// if he wants to drop the line - and should for errors.
// Also, if the user is being called back before the inline code
// has filled in the handle, then fill it in here - see comments in
// DCRNCConferenceManager::QueryRemote for additional background.
g_pCallbackInterface->OnQueryRemoteResult(
m_pOwner,
m_hr,
m_fRemoteIsMCU,
m_apConfNames,
m_pVersion,
m_apConfDescriptors);
// If we are not inline, and this request made it into
// the sequential work item list,
// then remove from list (which will cause item to be deleted),
// otherwise, just delete item.
g_pQueryRemoteList->RemoveWorkItem(this);
DebugExitVOID(CQueryRemoteWork::SyncQueryRemoteResult);
}
void CQueryRemoteWork::
AsyncQueryRemoteResult(void)
{
g_pNCConfMgr->PostWndMsg(NCMSG_QUERY_REMOTE_FAILURE, (LPARAM) this);
}
int CQueryRemoteWork::
GenerateRand(void)
{ // code from CRT
return (((m_nRandSeed = m_nRandSeed * 214013L + 2531011L) >> 16) & 0x7fff);
}
HRESULT CQueryRemoteWorkList::
Cancel ( LPVOID pCallerContext )
{
HRESULT hr = S_FALSE; // if not found
CQueryRemoteWork *p;
Reset();
while (NULL != (p = Iterate()))
{
if (p->IsOwnedBy(pCallerContext))
{
// clean up the underlying plumbing.
g_pIT120ControlSap->CancelConfQueryRequest(p->GetConnectionHandle());
// clean up node controller data.
RemoveWorkItem(p);
hr = S_OK;
break;
}
}
return hr;
}