|
|
//Copyright (c) 1998 - 1999 Microsoft Corporation
/*******************************************************************************
* * domain.cpp * * implementation of the CDomain class * * *******************************************************************************/
#include "stdafx.h"
#include "winadmin.h"
#include "admindoc.h"
#include "dialogs.h"
#include <malloc.h> // for alloca used by Unicode conversion macros
#include <mfc42\afxconv.h> // for Unicode conversion macros
static int _convert;
#include <winsta.h>
#include <regapi.h>
#include "..\..\inc\utilsub.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
#define MIN_MAJOR_VERSION 4
#define MIN_MINOR_VERSION 0
//////////////////////////////////////////////////////////////////////////////////////////
//
// CDomain Member Functions
//
//////////////////////////////////////////////////////////////////////////////////////////
CDomain::CDomain(TCHAR *name) { m_Flags = 0; m_PreviousState = DS_NONE; m_State = DS_NONE; m_hTreeItem = NULL; wcscpy(m_Name, name); m_pBackgroundThread = NULL; }
CDomain::~CDomain() { if(m_State == DS_ENUMERATING) StopEnumerating();
}
void CDomain::SetState(DOMAIN_STATE state) { // remember the previous state
m_PreviousState = m_State;
m_State = state;
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd(); if(p && ::IsWindow(p->GetSafeHwnd())) { p->SendMessage(WM_ADMIN_UPDATE_DOMAIN, 0, (LPARAM)this); } }
BOOL CDomain::StartEnumerating() { BOOL bResult = FALSE; LockBackgroundThread(); if( m_State == DS_ENUMERATING || m_State == DS_STOPPED_ENUMERATING ) { UnlockBackgroundThread( );
return FALSE; }
// Fire off the background thread for this domain
if( m_pBackgroundThread == NULL ) { DomainProcInfo *pProcInfo = new DomainProcInfo; if( pProcInfo != NULL ) { pProcInfo->pDomain = this; pProcInfo->pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument(); m_BackgroundContinue = TRUE; m_pBackgroundThread = AfxBeginThread((AFX_THREADPROC)CDomain::BackgroundThreadProc, pProcInfo, 0, CREATE_SUSPENDED, NULL );
if( m_pBackgroundThread == NULL ) { ODS( L"CDomain!StartEnumerating AfxBeginThread failed running low on resources\n" );
delete pProcInfo;
return FALSE; }
m_pBackgroundThread->m_bAutoDelete = FALSE;
if (m_pBackgroundThread->ResumeThread() <= 1) { bResult = TRUE; } } } UnlockBackgroundThread(); return TRUE; }
void CDomain::StopEnumerating() { // Tell the background thread to terminate and
// wait for it to do so.
LockBackgroundThread();
if(m_pBackgroundThread) { CWinThread *pBackgroundThread = m_pBackgroundThread; HANDLE hThread = m_pBackgroundThread->m_hThread; // Clear the pointer before releasing the lock
m_pBackgroundThread = NULL; ClearBackgroundContinue( );
UnlockBackgroundThread(); // Wait for the thread's death
if(WaitForSingleObject(hThread, 1000) == WAIT_TIMEOUT) { TerminateThread(hThread, 0); }
WaitForSingleObject(hThread, INFINITE); // delete the CWinThread object
delete pBackgroundThread; } else { UnlockBackgroundThread(); } SetState(DS_STOPPED_ENUMERATING);
DBGMSG( L"%s stopped enumerating\n" , GetName( ) ); }
USHORT Buflength(LPWSTR buf) { LPWSTR p = buf; USHORT length = 0;
while(*p) { USHORT plength = wcslen(p) + 1; length += plength; p += plength; }
return length;
} // end Buflength
LPWSTR ConcatenateBuffers(LPWSTR buf1, LPWSTR buf2) { // Make sure both buffer pointers are valid
if(!buf1 && !buf2) return NULL; if(buf1 && !buf2) return buf1; if(!buf1 && buf2) return buf2;
// figure out how big a buffer we'll need
USHORT buf1Length = Buflength(buf1); USHORT buf2Length = Buflength(buf2); USHORT bufsize = buf1Length + buf2Length + 1; // allocate a buffer
LPWSTR pBuffer = (LPWSTR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, bufsize * sizeof(WCHAR)); // If we can't allocate a buffer, free the second buffer and
// return the pointer to the first of the two buffers
if(!pBuffer) { LocalFree(buf2); return(buf1); }
LPWSTR p = pBuffer; // copy the contents of the first buffer into the new buffer
memcpy((char*)p, (char*)buf1, buf1Length * sizeof(WCHAR)); p += buf1Length; // copy the contents of the second buffer into the new buffer
memcpy((char*)p, (char*)buf2, buf2Length * sizeof(WCHAR));
LocalFree(buf1); LocalFree(buf2);
return pBuffer;
} // end ConcatenateBuffers
void CDomain::CreateServers(LPWSTR pBuffer, LPVOID _pDoc) { CWinAdminDoc *pDoc = (CWinAdminDoc*)_pDoc; CWinAdminApp *pApp = (CWinAdminApp*)AfxGetApp(); LPWSTR pTemp = pBuffer; // Loop through all the WinFrame servers that we found
while(*pTemp) { // The server's name is in pTemp
// Find the server in our list
CServer *pServer = pDoc->FindServerByName(pTemp); // If the server is in our list, set the flag to say we found it
if(pServer) { pServer->SetBackgroundFound();
if( pServer->GetTreeItem( ) == NULL ) { CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd(); p->SendMessage(WM_ADMIN_ADD_SERVER, ( WPARAM )TVI_SORT, (LPARAM)pServer); }
} else { // We don't want to add the current Server again
if( lstrcmpi( pTemp , pApp->GetCurrentServerName() ) ) { // Create a new server object
CServer *pNewServer = new CServer(this, pTemp, FALSE, pDoc->ShouldConnect(pTemp)); if(pNewServer != NULL ) { // Add the server object to our linked list
pDoc->AddServer(pNewServer); // Set the flag to say we found it
pNewServer->SetBackgroundFound(); CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd(); if(p && ::IsWindow(p->GetSafeHwnd())) { p->SendMessage(WM_ADMIN_ADD_SERVER, ( WPARAM )TVI_SORT, (LPARAM)pNewServer); } } } } // Go to the next server in the buffer
pTemp += (wcslen(pTemp) + 1); } // end while (*pTemp)
}
/////////////////////////////////////////////////////////////////////////////
// CDomain::BackgroundThreadProc
//
// Static member function for background thread
// Looks for servers appearing and disappearing
// Called with AfxBeginThread
// Thread terminates when function returns
//
UINT CDomain::BackgroundThreadProc(LPVOID bg) { // We need a pointer to the document so we can make
// calls to member functions
CWinAdminDoc *pDoc = (CWinAdminDoc*)((DomainProcInfo*)bg)->pDoc; CDomain *pDomain = ((DomainProcInfo*)bg)->pDomain; delete bg; CWinAdminApp *pApp = (CWinAdminApp*)AfxGetApp(); // We want to keep track of whether or not we've enumerated - so
// that we can update the tree when we're done
BOOL bNotified = FALSE; // We can't send messages to the view until they're ready
// v-nicbd RESOLVED In case we are exiting tsadmin, we are waiting uselessly here
// - 500ms lapsed is negligible in UI
while( !pDoc->AreAllViewsReady() ) { Sleep(500); } // Don't do this until the views are ready!
pDomain->SetState(DS_INITIAL_ENUMERATION); // If there is an extension DLL loaded, we will allow it to enumerate
// additional servers
LPFNEXENUMERATEPROC EnumerateProc = pApp->GetExtEnumerationProc(); // The first time we enumerate servers, we want the CServer object
// to put the server in the views when it has enough info.
// On subsequent enumerations, we will add the server to the views
// here.
BOOL bSubsequent = FALSE; while(pDomain->ShouldBackgroundContinue()) { BOOL Enumerated = FALSE; CObList TempServerList; DBGMSGx( L"CDomain!BackgroundThreadProc %s still going thread %d\n" , pDomain->GetName( ) , GetCurrentThreadId( ) ); // Loop through all the servers and turn off the flag
// that tells this thread that he found it on this pass
pDoc->LockServerList(); CObList *pServerList = pDoc->GetServerList(); POSITION pos = pServerList->GetHeadPosition(); while(pos) { POSITION pos2 = pos; CServer *pServer = (CServer*)pServerList->GetNext(pos); if(pServer->GetDomain() == pDomain) { pServer->ClearBackgroundFound(); // We want to remove a server if we could see it
// the last time we enumerated servers
// NOTE: This should not cause any problems
// The views should no longer have items pointing
// to this server at this point
//
// Move the server object to a temporary list.
// This is so that we can unlock the server list before
// we call the destructor on a CServer object since the
// destructor will end up calling SetState() which does
// a SendMessage. This is not good to do with the list
// locked.
if(pServer->IsServerInactive() && !pServer->IsCurrentServer()) { pServer = (CServer*)pServerList->GetAt(pos2); // Remove it from the server list
DBGMSG( L"Adding %s to temp list to destroy\n" , pServer->GetName( ) ); pServerList->RemoveAt(pos2); // Add it to our temporary list
TempServerList.AddTail(pServer); } } } pDoc->UnlockServerList(); // do a first loop to signal the servers' background threads that they must stop
pos = TempServerList.GetHeadPosition(); while(pos) { CServer *pServer = (CServer*)TempServerList.GetNext(pos); DBGMSG( L"Clearing %s backgrnd cont\n", pServer->GetName() ); pServer->ClearBackgroundContinue(); } // do a second loop to disconnect and delete the servers
pos = TempServerList.GetHeadPosition(); while(pos) { CServer *pServer = (CServer*)TempServerList.GetNext(pos); DBGMSG( L"Disconnecting and deleteing %s now!!!\n", pServer->GetName( ) ); pServer->Disconnect( ); delete pServer; ODS( L"gone.\n" ); } TempServerList.RemoveAll(); // Make sure we don't have to quit
if(!pDomain->ShouldBackgroundContinue()) { return 0; } // Get all the Servers now (we already got the current server)
LPWSTR pBuffer = NULL; // Find all WinFrame servers in the domain
pBuffer = pDomain->EnumHydraServers(/*pDomain->GetName(),*/ MIN_MAJOR_VERSION, MIN_MINOR_VERSION); // Make sure we don't have to quit
if(!pDomain->ShouldBackgroundContinue()) { if(pBuffer) LocalFree(pBuffer); return 0; } // Make sure we don't have to quit
if(!pDomain->ShouldBackgroundContinue()) { if(pBuffer) LocalFree(pBuffer); return 0; } if(pBuffer) { Enumerated = TRUE; pDomain->CreateServers(pBuffer, (LPVOID)pDoc); LocalFree(pBuffer); } // end if(pBuffer)
// Make sure we don't have to quit
if(!pDomain->ShouldBackgroundContinue()) return 0; if(!bNotified) { pDomain->SetState(DS_ENUMERATING); bNotified = TRUE; } // If there is an extension DLL loaded, allow it to enumerate additional servers
LPWSTR pExtBuffer = NULL; if(EnumerateProc) { pExtBuffer = (*EnumerateProc)(pDomain->GetName()); } // If the extension DLL found servers, concatenate the two buffers
// The ConcatenateBuffers function will delete both buffers and return a
// pointer to the new buffer
if(pExtBuffer) { Enumerated = TRUE; pDomain->CreateServers(pExtBuffer, (LPVOID)pDoc); LocalFree(pExtBuffer); } // Make sure we don't have to quit
if(!pDomain->ShouldBackgroundContinue()) { return 0; } if(Enumerated) { // Mark the current server as found
CServer *pCurrentServer = pDoc->GetCurrentServer(); if(pCurrentServer) pCurrentServer->SetBackgroundFound(); // Go through the list of servers and see which ones don't have
// the flag set saying that we found it
CObList TempList; pDoc->LockServerList(); pServerList = pDoc->GetServerList(); POSITION pos = pServerList->GetHeadPosition(); while(pos) { CServer *pServer = (CServer*)pServerList->GetNext(pos); if(pServer->GetDomain() == pDomain) { // we check to see if this server has been initially inserted to our server list
// manually. If so we don't want it inserted to our templist for deletion.
if( !pServer->IsManualFind() && ( !pServer->IsBackgroundFound() || pServer->HasLostConnection() || !pServer->IsServerSane() ) ) { DBGMSG( L"Removing %s background not found or lost connection\n" , pServer->GetName( ) ); // Set the flag to say that this server is inactive
pServer->SetServerInactive(); // Add it to our temporary list
TempList.AddTail(pServer); } } } pDoc->UnlockServerList(); pos = TempList.GetHeadPosition(); CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd(); while(pos) { CServer *pServer = (CServer*)TempList.GetNext(pos); // Send a message to the mainframe to remove the server
if(p && ::IsWindow(p->GetSafeHwnd())) { DBGMSG( L"CDomain!Bkthrd removing %s temped threads from treeview & view\n" , pServer->GetName( ) ); // clean up old node
if( pServer->GetTreeItemFromFav( ) != NULL ) { // we cannot keep a favnode around if a server node is being deleted
// massive AV's will occurr. So a quick fix is to remove the favnode
// if it exists and create a new server node and mark it as manually
// found. This will prevent this server node from being removed in
// case NetEnumServer fails to pick up this server
p->SendMessage( WM_ADMIN_REMOVESERVERFROMFAV , TRUE , ( LPARAM )pServer ); CServer *ptServer = new CServer( pDomain , pServer->GetName( ) , FALSE , FALSE ); if( ptServer != NULL ) { ptServer->SetManualFind( ); pDoc->AddServer(ptServer); p->SendMessage(WM_ADMIN_ADDSERVERTOFAV , 0 , (LPARAM)ptServer); } } p->SendMessage(WM_ADMIN_REMOVE_SERVER, TRUE, (LPARAM)pServer); } } TempList.RemoveAll(); } // end if(Enumerated)
// We don't want to do this constantly, it eats up processor cycles to enumerate servers
// so we'll now let the user refresh these servers manually
// Document destructor will signal the event to wake us up if he
// wants us to quit
pDomain->m_WakeUpEvent.Lock( INFINITE ); bSubsequent = TRUE; } // end while(1)
return 0; } // end CDomain::BackgroundThreadProc
/*******************************************************************************
* * EnumHydraServers - Hydra helper function (taken from utildll and modified * to be used along with a version check. * * Enumerate the Hydra servers on the network by Domain * Returns all the servers whose version is >= the version passed. * * ENTRY: * pDomain (input) * Specifies the domain to enumerate; NULL for current domain. * verMajor (input) * specifies the Major version to check for. * verMinor (input) * specifies the minor version to check for. * * EXIT: * (LPTSTR) Points to LocalAlloced buffer containing results of the * enumeration, in multi-string format, if sucessful; NULL if * error. The caller must perform a LocalFree of this buffer * when done. If error (NULL), the error code is set for * retrieval by GetLastError(); * ******************************************************************************/ LPWSTR CDomain::EnumHydraServers( /*LPWSTR pDomain,*/ DWORD verMajor, DWORD verMinor )
{ PSERVER_INFO_101 pInfo = NULL; DWORD dwByteCount, dwIndex, TotalEntries; DWORD AvailCount = 0; LPWSTR pTemp, pBuffer = NULL;
/*
* Enumerate all WF servers on the specified domain. */ if ( NetServerEnum ( NULL, 101, (LPBYTE *)&pInfo, (DWORD) -1, &AvailCount, &TotalEntries, SV_TYPE_TERMINALSERVER, m_Name, /*pDomain,*/ NULL ) || !AvailCount ) goto done;
//
// Traverse list of the servers that match the major and minor versions'criteria
// and calculate the total byte count for list of
// servers that will be returned.
//
for( dwByteCount = dwIndex = 0; dwIndex < AvailCount; dwIndex++ ) { if( ((pInfo[dwIndex].sv101_version_major & MAJOR_VERSION_MASK) >= verMajor) && (pInfo[dwIndex].sv101_version_minor >= verMinor) ) { dwByteCount += (wcslen(pInfo[dwIndex].sv101_name) + 1) * 2; } }
dwByteCount += 2; // for ending null
/*
* Allocate memory. */ if( (pBuffer = (LPWSTR)LocalAlloc(LPTR, dwByteCount)) == NULL ) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto done; }
/*
* Traverse list again and copy servers to buffer. */ for( pTemp = pBuffer, dwIndex = 0; dwIndex < AvailCount; dwIndex++ ) { if( ((pInfo[dwIndex].sv101_version_major & MAJOR_VERSION_MASK) >= verMajor) && (pInfo[dwIndex].sv101_version_minor >= verMinor) ) { // MS Bug 1821
if ( wcslen(pInfo[dwIndex].sv101_name) != 0 ) { wcscpy(pTemp, pInfo[dwIndex].sv101_name);
pTemp += (wcslen(pInfo[dwIndex].sv101_name) + 1); } } } *pTemp = L'\0'; // ending null
done: if( AvailCount && pInfo ) { NetApiBufferFree( pInfo ); } return(pBuffer); } // end CDomain::EnumHydraServers
/////////////////////////////////////////////////////////////////////////////
// CDomain::DisconnectAllServers
//
// Disconnect from all servers in this Domain
//
void CDomain::DisconnectAllServers() { CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CObList *pServerList = pDoc->GetServerList();
CString AString; CDialog dlgWait; dlgWait.Create(IDD_SHUTDOWN, NULL);
pDoc->LockServerList();
ODS( L"TSADMIN:CDomain::DisconnectAllServers about to disconnect all connected servers\n" );
// Do a first loop to signal the server background threads that they must stop
POSITION pos = pServerList->GetHeadPosition(); while(pos) { // Get a pointer to the server
CServer *pServer = (CServer*)pServerList->GetNext(pos); // If this Server is in the domain and connected, tell the server background thread to stop
if(pServer->GetDomain() == this && pServer->GetState() != SS_NOT_CONNECTED) { pServer->ClearBackgroundContinue(); } } // do a second loop to disconnect the servers
pos = pServerList->GetHeadPosition(); while(pos) { // Get a pointer to the server
CServer *pServer = (CServer*)pServerList->GetNext(pos); // If this Server is in the domain and connected, disconnect from it
if ((pServer->GetDomain() == this) && (pServer->GetState() != SS_NOT_CONNECTED)) { AString.Format(IDS_DISCONNECTING, pServer->GetName()); dlgWait.SetDlgItemText(IDC_SHUTDOWN_MSG, AString);
// Tell the server to connect
pServer->Disconnect(); } }
//
// tell domain not to connect to any more servers
//
pDoc->UnlockServerList();
dlgWait.PostMessage(WM_CLOSE);
} // end CDomain::DisconnectAllServers
/////////////////////////////////////////////////////////////////////////////
// CDomain::ConnectAllServers
//
// Connect to all servers in this Domain
//
void CDomain::ConnectAllServers() { CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CObList *pServerList = pDoc->GetServerList();
pDoc->LockServerList();
POSITION pos = pServerList->GetHeadPosition(); while(pos) { // Get a pointer to the server
CServer *pServer = (CServer*)pServerList->GetNext(pos); // If this Server is int the domain and not connected, connect to it
if(pServer->GetDomain() == this && pServer->IsState(SS_NOT_CONNECTED)) { // Tell the server to connect
pServer->Connect(); } }
pDoc->UnlockServerList();
} // end CDomain::ConnectAllServers
|