/*++ 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 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 * pNTDirectory; hr = CComObject::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 * pILSDirectory; hr = CComObject::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 * pNDNCDirectory; hr = CComObject::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 &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 CCopy; typedef CSafeComEnum CEnumerator; HRESULT hr; CComObject *pEnum = NULL; hr = CComObject::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 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 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