648 lines
14 KiB
C++
648 lines
14 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
rndrend.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains implementation of CRendezvous control.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include "rndrend.h"
|
||
|
#include "rndcoll.h"
|
||
|
#include "rndreg.h"
|
||
|
#include "rndnt.h"
|
||
|
#include "rndils.h"
|
||
|
#include "rndndnc.h"
|
||
|
#include "rndldap.h"
|
||
|
|
||
|
#include <atlwin.cpp>
|
||
|
|
||
|
|
||
|
CRegistry g_RregistryInfo;
|
||
|
|
||
|
CRendezvous::~CRendezvous()
|
||
|
{
|
||
|
if (m_fWinsockReady)
|
||
|
{
|
||
|
WSACleanup();
|
||
|
}
|
||
|
|
||
|
if ( m_pFTM )
|
||
|
{
|
||
|
m_pFTM->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CRendezvous::FinalConstruct(void)
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRendezvous::FinalConstruct - enter"));
|
||
|
|
||
|
HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
|
||
|
& m_pFTM );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_INFO, "CRendezvous::FinalConstruct - "
|
||
|
"create FTM returned 0x%08x; exit", hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
LOG((MSP_TRACE, "CRendezvous::FinalConstruct - exit S_OK"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Private functions
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
HRESULT CRendezvous::InitWinsock()
|
||
|
{
|
||
|
Lock();
|
||
|
|
||
|
if (!m_fWinsockReady)
|
||
|
{
|
||
|
WSADATA wsaData;
|
||
|
int err;
|
||
|
|
||
|
// initialize winsock
|
||
|
if (err = WSAStartup(RENDWINSOCKVERSION, &wsaData))
|
||
|
{
|
||
|
Unlock();
|
||
|
return HRESULT_FROM_ERROR_CODE(err);
|
||
|
}
|
||
|
m_fWinsockReady = TRUE;
|
||
|
}
|
||
|
|
||
|
Unlock();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CRendezvous::CreateNTDirectory(
|
||
|
OUT ITDirectory **ppDirectory
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Create a object that uses NTDS to support the ITDirectory.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ppDirectory - the object being created.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// create the NTDS directory, if NTDS exists.
|
||
|
CComObject<CNTDirectory> * pNTDirectory;
|
||
|
hr = CComObject<CNTDirectory>::CreateInstance(&pNTDirectory);
|
||
|
|
||
|
if (NULL == pNTDirectory)
|
||
|
{
|
||
|
LOG((MSP_ERROR, "can't create NT Directory Object."));
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pNTDirectory->_InternalQueryInterface(
|
||
|
IID_ITDirectory,
|
||
|
(void **)ppDirectory
|
||
|
);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CreateNTDirectory:QueryInterface failed: %x", hr));
|
||
|
delete pNTDirectory;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CRendezvous::CreateILSDirectory(
|
||
|
IN const WCHAR * const wstrName,
|
||
|
IN const WORD wPort,
|
||
|
OUT ITDirectory ** ppDirectory
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Create a object that uses ILS to support the ITDirectory.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
wstrName - The ILS server name.
|
||
|
|
||
|
wPort - The port that the server is listening on.
|
||
|
|
||
|
ppDirectory - the object being created.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// create the com object.
|
||
|
CComObject<CILSDirectory> * pILSDirectory;
|
||
|
hr = CComObject<CILSDirectory>::CreateInstance(&pILSDirectory);
|
||
|
|
||
|
if (NULL == pILSDirectory)
|
||
|
{
|
||
|
LOG((MSP_ERROR, "can't create ILS Directory Object."));
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// init the object with the server name and port.
|
||
|
hr = pILSDirectory->Init(wstrName, wPort);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CreateILSDirectory:Init failed: %x", hr));
|
||
|
delete pILSDirectory;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// get the ITDirectory interface.
|
||
|
hr = pILSDirectory->_InternalQueryInterface(
|
||
|
IID_ITDirectory,
|
||
|
(void **)ppDirectory
|
||
|
);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CreateILSDirectory:QueryInterface failed: %x", hr));
|
||
|
delete pILSDirectory;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CRendezvous::CreateNDNCDirectory(
|
||
|
IN const WCHAR * const wstrName,
|
||
|
IN const WORD wPort,
|
||
|
OUT ITDirectory ** ppDirectory
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Create a object that uses an NDNC to support the ITDirectory.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
wstrName - The NDNC server name.
|
||
|
|
||
|
wPort - The port that the server is listening on.
|
||
|
|
||
|
ppDirectory - the object being created.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRendezvous::CreateNDNCDirectory - enter"));
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
//
|
||
|
// create the com object.
|
||
|
//
|
||
|
|
||
|
CComObject<CNDNCDirectory> * pNDNCDirectory;
|
||
|
hr = CComObject<CNDNCDirectory>::CreateInstance(&pNDNCDirectory);
|
||
|
|
||
|
if ( NULL == pNDNCDirectory )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CreateNDNCDirectory - "
|
||
|
"can't create NDNC Directory Object - exit 0x%08x", hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get the ITDirectory interface.
|
||
|
//
|
||
|
|
||
|
hr = pNDNCDirectory->_InternalQueryInterface(
|
||
|
IID_ITDirectory,
|
||
|
(void **)ppDirectory
|
||
|
);
|
||
|
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CreateNDNCDirectory - "
|
||
|
"QueryInterface failed - exit 0x%08x", hr));
|
||
|
|
||
|
delete pNDNCDirectory;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// init the object with the server name and port.
|
||
|
// For NDNCs, this also looks around on the server and tries to
|
||
|
// see where on the server the NDNC is supposed to live. If there
|
||
|
// is no TAPI NDNC in the domain, this will fail. Therefore, when
|
||
|
// enumerating default directories, the local DC won't show up as
|
||
|
// an NDNC if there is no NDNC accessible from the local DC.
|
||
|
//
|
||
|
|
||
|
hr = pNDNCDirectory->Init(wstrName, wPort);
|
||
|
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CreateNDNCDirectory - "
|
||
|
"Init failed - exit 0x%08x", hr));
|
||
|
|
||
|
(*ppDirectory)->Release();
|
||
|
*ppDirectory = NULL;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
LOG((MSP_TRACE, "CRendezvous::CreateNDNCDirectory - exit S_OK"));
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CRendezvous::CreateDirectories(
|
||
|
SimpleVector <ITDirectory *> &VDirectory
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Find out all the direcories that are available.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pppDirectory - the array of directories being created.
|
||
|
|
||
|
dwCount - The number of directories.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
LOG((MSP_TRACE, "CreateDirectories: "));
|
||
|
|
||
|
ITDirectory * pDirectory;
|
||
|
|
||
|
//
|
||
|
// First, create the NTDS non-dynamic directory object.
|
||
|
//
|
||
|
|
||
|
if (SUCCEEDED(hr = CreateNTDirectory(&pDirectory)))
|
||
|
{
|
||
|
if (!VDirectory.add(pDirectory))
|
||
|
{
|
||
|
pDirectory->Release();
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LOG((MSP_WARN, "Cannot create NT directory: 0x%08x", hr));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Second, create the NDNC directory object.
|
||
|
//
|
||
|
|
||
|
WCHAR * pDomainControllerName;
|
||
|
|
||
|
//
|
||
|
// The first argument (=0) means we find out all
|
||
|
// objects
|
||
|
//
|
||
|
|
||
|
hr = GetDomainControllerName(0, &pDomainControllerName);
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = CreateNDNCDirectory(
|
||
|
pDomainControllerName,
|
||
|
LDAP_PORT,
|
||
|
&pDirectory
|
||
|
);
|
||
|
|
||
|
delete pDomainControllerName;
|
||
|
|
||
|
if ( SUCCEEDED( hr ) )
|
||
|
{
|
||
|
if (!VDirectory.add(pDirectory))
|
||
|
{
|
||
|
pDirectory->Release();
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LOG((MSP_WARN, "Cannot create NDNC directory: 0x%08x", hr));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LOG((MSP_WARN, "Cannot get DC name: 0x%08x", hr));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Third, find out if there are any ILS servers published in the NTDS.
|
||
|
//
|
||
|
|
||
|
HANDLE hLookup;
|
||
|
int ret = ::LookupILSServiceBegin(&hLookup);
|
||
|
|
||
|
if (ret != NOERROR)
|
||
|
{
|
||
|
LOG((MSP_WARN, "Lookup ILSservice failed: 0x%08x", ret));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const DWORD MAX_HOST_NAME_LEN = 511;
|
||
|
WCHAR HostName[MAX_HOST_NAME_LEN + 1];
|
||
|
DWORD dwLen = MAX_HOST_NAME_LEN;
|
||
|
WORD wPort;
|
||
|
|
||
|
while (::LookupILSServiceNext(
|
||
|
hLookup,
|
||
|
HostName,
|
||
|
&dwLen,
|
||
|
&wPort
|
||
|
) == NOERROR)
|
||
|
{
|
||
|
LOG((MSP_INFO, "ILS server in NTDS: %S, Port:%d",
|
||
|
HostName, wPort));
|
||
|
|
||
|
hr = CreateILSDirectory(HostName, wPort, &pDirectory);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (!VDirectory.add(pDirectory))
|
||
|
{
|
||
|
pDirectory->Release();
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LOG((MSP_WARN, "Cannot create ILS directory: 0x%08x", hr));
|
||
|
}
|
||
|
|
||
|
dwLen = MAX_HOST_NAME_LEN;
|
||
|
}
|
||
|
::LookupILSServiceEnd(hLookup);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CRendezvous::CreateDirectoryEnumerator(
|
||
|
IN ITDirectory ** begin,
|
||
|
IN ITDirectory ** end,
|
||
|
OUT IEnumDirectory ** ppIEnum
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Create a enumerator of directories.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
begin - The start iterator.
|
||
|
|
||
|
end - The end iterator.
|
||
|
|
||
|
ppIEnum - The enumerator being created.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
typedef _CopyInterface<ITDirectory> CCopy;
|
||
|
typedef CSafeComEnum<IEnumDirectory, &IID_IEnumDirectory,
|
||
|
ITDirectory *, CCopy> CEnumerator;
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
CComObject<CEnumerator> *pEnum = NULL;
|
||
|
|
||
|
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
|
||
|
if (pEnum == NULL)
|
||
|
{
|
||
|
LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pEnum->Init(begin, end, NULL, AtlFlagCopy);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
|
||
|
delete pEnum;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// query for the IID_IEnumDirectory i/f
|
||
|
hr = pEnum->_InternalQueryInterface(IID_IEnumDirectory, (void**)ppIEnum);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "query enum interface failed, %x", hr));
|
||
|
delete pEnum;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// ITRendezvous
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
STDMETHODIMP CRendezvous::get_DefaultDirectories(
|
||
|
OUT VARIANT * pVariant
|
||
|
)
|
||
|
{
|
||
|
if (BadWritePtr(pVariant))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "bad variant pointer in get_DefaultDirectories"));
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
BAIL_IF_FAIL(InitWinsock(), "Init winsock");
|
||
|
|
||
|
// create the default directories.
|
||
|
SimpleVector <ITDirectory *> VDirectory;
|
||
|
CreateDirectories(VDirectory);
|
||
|
|
||
|
// create the collection.
|
||
|
HRESULT hr = ::CreateInterfaceCollection(VDirectory.size(),
|
||
|
&VDirectory[0],
|
||
|
&VDirectory[VDirectory.size()],
|
||
|
pVariant);
|
||
|
|
||
|
// the collection has its ref count, so release local ones.
|
||
|
for (DWORD i = 0; i < VDirectory.size(); i ++)
|
||
|
{
|
||
|
VDirectory[i]->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CRendezvous::EnumerateDefaultDirectories(
|
||
|
OUT IEnumDirectory ** ppEnumDirectory
|
||
|
)
|
||
|
{
|
||
|
if (BadWritePtr(ppEnumDirectory))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "bad pointer in EnumerateDefaultDirectories"));
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
BAIL_IF_FAIL(InitWinsock(), "Init winsock");
|
||
|
|
||
|
// create the default directories.
|
||
|
SimpleVector <ITDirectory *> VDirectory;
|
||
|
CreateDirectories(VDirectory);
|
||
|
|
||
|
// create the enumerator
|
||
|
HRESULT hr = CreateDirectoryEnumerator(
|
||
|
&VDirectory[0],
|
||
|
&VDirectory[VDirectory.size()],
|
||
|
ppEnumDirectory
|
||
|
);
|
||
|
|
||
|
for (DWORD i = 0; i < VDirectory.size(); i ++)
|
||
|
{
|
||
|
VDirectory[i]->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CRendezvous::CreateDirectory(
|
||
|
IN DIRECTORY_TYPE DirectoryType,
|
||
|
IN BSTR pName,
|
||
|
OUT ITDirectory ** ppDir
|
||
|
)
|
||
|
{
|
||
|
if (BadWritePtr(ppDir))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "bad pointer in CreateDirectory"));
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We should validate the pName
|
||
|
// If is NULL we should return E_INVALIDARG
|
||
|
//
|
||
|
|
||
|
if( IsBadStringPtr( pName, (UINT)-1))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "bad Name pointer in CreateDirectory"));
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
BAIL_IF_FAIL(InitWinsock(), "Init winsock");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
switch (DirectoryType)
|
||
|
{
|
||
|
case DT_NTDS:
|
||
|
hr = CreateNTDirectory(ppDir);
|
||
|
break;
|
||
|
|
||
|
case DT_ILS:
|
||
|
|
||
|
//
|
||
|
// Try NDNC first, as ILS is legacy. The CreateNDNCDirectory actually
|
||
|
// goes on the wire and checks if it looks like an NDNC server; the
|
||
|
// CreateILSDirectory does no such thing. This maintains the ability
|
||
|
// to use custom ports with ILS, and it also preserves the semantics
|
||
|
// of not getting a failure returned for a bad server name until you
|
||
|
// call ITDirectory::Connect.
|
||
|
//
|
||
|
|
||
|
hr = CreateNDNCDirectory(pName, LDAP_PORT, ppDir);
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
hr = CreateILSDirectory(pName, ILS_PORT, ppDir);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LOG((MSP_ERROR, "unknown directory type, %x", DirectoryType));
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CRendezvous::CreateDirectoryObject(
|
||
|
IN DIRECTORY_OBJECT_TYPE DirectoryObjectType,
|
||
|
IN BSTR pName,
|
||
|
OUT ITDirectoryObject ** ppDirectoryObject
|
||
|
)
|
||
|
{
|
||
|
if (BadWritePtr(ppDirectoryObject))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "bad pointer in CreateDirectoryObject"));
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
BAIL_IF_FAIL(InitWinsock(), "Init winsock");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
switch (DirectoryObjectType)
|
||
|
{
|
||
|
case OT_CONFERENCE:
|
||
|
hr = ::CreateEmptyConference(pName, ppDirectoryObject);
|
||
|
break;
|
||
|
|
||
|
case OT_USER:
|
||
|
hr = ::CreateEmptyUser(pName, ppDirectoryObject);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LOG((MSP_ERROR, "unknown directory type, %x", DirectoryObjectType));
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
return hr; // ZoltanS fix 6-1-98
|
||
|
}
|
||
|
|
||
|
// eof
|