Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1047 lines
25 KiB

#include "precomp.h"
#pragma hdrstop
#include "private.h"
#include "engine.h"
#include "resource.h"
#include "Document.h"
#include "Application.h"
#include "MainForm.h"
#include "AboutDialog.h"
#include "application.tmh"
#include <process.h>
Application theApplication;
MUsingCom usingCom;
BOOL CanRunNLB(void);
BEGIN_MESSAGE_MAP( Application, CWinApp )
ON_COMMAND( ID_HELP, OnHelp )
ON_COMMAND( ID_APP_ABOUT, OnAppAbout )
END_MESSAGE_MAP()
// #define szNLBMGRREG_DISABLE_DISCLAIMER L"DisableNlbMgrDisclaimer"
#if DBG
//
// Allow the DEMO cmdline option
//
#define ALLOW_DEMO 1
#endif //DBG
BOOL NoAdminNics(void);
void
CNlbMgrCommandLineInfo::ParseParam(
LPCTSTR lpszParam,
BOOL bFlag,
BOOL bLast
)
//
// -demo
// -hostlist file.txt
// -help -?
// -autoresfresh
// -noping
{
static enum Commands {
None = 0,
Demo,
NoPing,
HostList,
AutoRefresh
};
static UINT LastCommand = None;
TRACE_VERB("-> %!FUNC! (szParm=\"%ws\", bFlag=%lu, bLast=%lu)", lpszParam, bFlag, bLast);
if (m_bUsage)
{
goto end;
}
if (bFlag)
{
/* Throw an error if this is a flag, but the last command was the
HostList command, which REQUIRES a non-flag argument following it. */
if (LastCommand == HostList)
{
/* Turn the host list option off to keep NLB manager
from trying to open NULL filename. */
m_bHostList = FALSE;
m_bUsage = TRUE; // error
goto end;
}
#if ALLOW_DEMO
if (!_wcsicmp(lpszParam, L"demo"))
{
if (m_bDemo)
{
m_bUsage = TRUE; // error
goto end;
}
m_bDemo = TRUE;
LastCommand = Demo;
}
else
#endif // ALLOW_DEMO
if (!_wcsicmp(lpszParam, L"noping"))
{
if (m_bNoPing)
{
m_bUsage = TRUE; // error
goto end;
}
m_bNoPing = TRUE;
LastCommand = NoPing;
}
else if (!_wcsicmp(lpszParam, L"hostlist"))
{
if (m_bHostList || bLast)
{
m_bUsage = TRUE; // error
goto end;
}
m_bHostList = TRUE;
LastCommand = HostList;
}
else if (!_wcsicmp(lpszParam, L"autorefresh"))
{
if (m_bAutoRefresh)
{
m_bUsage = TRUE; // error
goto end;
}
m_bAutoRefresh = TRUE;
LastCommand = AutoRefresh;
}
else
{
m_bUsage = TRUE; // error or help
}
}
else
{
switch (LastCommand) {
case None:
m_bUsage = TRUE; // error
break;
case Demo:
m_bUsage = TRUE; // error
break;
case NoPing:
m_bUsage = TRUE; // error
break;
case HostList:
m_bstrHostListFile = _bstr_t(lpszParam); // read the file name of the host list
break;
case AutoRefresh:
m_refreshInterval = _wtoi(lpszParam); // read the refresh interval
/* If the specified refresh interval is too small to be practical, re-set it. */
if (m_refreshInterval < NLBMGR_AUTOREFRESH_MIN_INTERVAL)
m_refreshInterval = NLBMGR_AUTOREFRESH_MIN_INTERVAL;
break;
default:
m_bUsage = TRUE; // error
break;
}
/* Re-set the last command. */
LastCommand = None;
}
end:
TRACE_VERB("%!FUNC! <-");
}
BOOL
Application::ProcessShellCommand(
CNlbMgrCommandLineInfo& rCmdInfo
)
{
BOOL fRet = FALSE;
LPCWSTR szFile = NULL;
TRACE_CRIT("-> %!FUNC!");
fRet = CWinApp::ProcessShellCommand(rCmdInfo);
if (!fRet)
{
goto end;
}
szFile = (LPCWSTR) rCmdInfo.m_bstrHostListFile;
if (szFile==NULL)
{
szFile = L"<null>";
}
TRACE_VERB("%!FUNC! bUsage=%lu bDemo=%lu bNoPing=%lu bHostList=%lu szFile=\"%ws\"",
rCmdInfo.m_bUsage,
rCmdInfo.m_bDemo,
rCmdInfo.m_bNoPing,
rCmdInfo.m_bHostList,
szFile
);
if (rCmdInfo.m_bUsage)
{
_bstr_t bstrMsg = GETRESOURCEIDSTRING( IDS_USAGE_MESSAGE );
_bstr_t bstrTitle = GETRESOURCEIDSTRING( IDS_USAGE_TITLE );
::MessageBox(
NULL,
(LPCWSTR) bstrMsg,
(LPCWSTR) bstrTitle,
MB_ICONINFORMATION | MB_OK
);
fRet = FALSE;
}
else
{
if (rCmdInfo.m_bDemo)
{
_bstr_t bstrMsg = GETRESOURCEIDSTRING( IDS_DEMO_MESSAGE );
_bstr_t bstrTitle = GETRESOURCEIDSTRING( IDS_DEMO_TITLE );
::MessageBox(
NULL,
(LPCWSTR) bstrMsg,
(LPCWSTR) bstrTitle,
MB_ICONINFORMATION | MB_OK
);
}
fRet = TRUE;
}
end:
TRACE_CRIT("<- %!FUNC! returns %lu", fRet);
return fRet;
}
BOOL
Application::InitInstance()
{
BOOL fRet = FALSE;
WPP_INIT_TRACING(L"Microsoft\\NLB\\TPROV");
TRACE_INFO("------------ APPLICATION INITITIALIZATION -------------");
//
// Set the current thread id as the main thread id
//
m_dwMainThreadId = GetCurrentThreadId();
ParseCommandLine(gCmdLineInfo);
m_pSingleDocumentTemplate =
new CSingleDocTemplate( IDR_MAINFRAME,
RUNTIME_CLASS( Document ),
RUNTIME_CLASS( MainForm ),
RUNTIME_CLASS( LeftView) );
AddDocTemplate( m_pSingleDocumentTemplate );
//
// NOTE: ProcessShellCommand is our (Application) own version. It
// calls CWinApp::ProcessShellCommand.
//
fRet = ProcessShellCommand( gCmdLineInfo );
if (!fRet)
{
goto end;
}
fRet = CanRunNLB();
// fall through...
end:
if (!fRet)
{
// Deinit tracing here.
WPP_CLEANUP();
}
return fRet;
}
void
Application::OnAppAbout()
{
AboutDialog aboutDlg;
aboutDlg.DoModal();
}
void
Application::OnHelp()
{
WCHAR wbuf[CVY_STR_SIZE];
/* Spawn the windows help process. */
StringCbPrintf(wbuf, sizeof(wbuf), L"%ls\\help\\%ls", _wgetenv(L"WINDIR"), CVY_HELP_FILE);
_wspawnlp(P_NOWAIT, L"hh.exe", L"hh.exe", wbuf, NULL);
}
BOOL CanRunNLB(void)
/*
Checks if NLB can run on the current machine. The main check is to make sure that there is atleast one active NIC without NLB bound.
*/
{
if (NoAdminNics())
{
::MessageBox(
NULL,
GETRESOURCEIDSTRING( IDS_CANTRUN_NONICS_TEXT), // Contents
GETRESOURCEIDSTRING( IDS_CANTRUN_NONICS_CAPTION), // caption
MB_ICONSTOP | MB_OK );
}
else
{
// ::ShowDisclaimer();
}
return TRUE;
}
//
// This class manages NetCfg interfaces
//
class AppMyNetCfg
{
public:
AppMyNetCfg(VOID)
{
m_pINetCfg = NULL;
m_pLock = NULL;
}
~AppMyNetCfg()
{
ASSERT(m_pINetCfg==NULL);
ASSERT(m_pLock==NULL);
}
WBEMSTATUS
Initialize(
BOOL fWriteLock
);
VOID
Deinitialize(
VOID
);
WBEMSTATUS
GetNlbCompatibleNics(
OUT LPWSTR **ppszNics,
OUT UINT *pNumNics,
OUT UINT *pNumBoundToNlb // OPTIONAL
);
WBEMSTATUS
GetBindingIF(
IN LPCWSTR szComponent,
OUT INetCfgComponentBindings **ppIBinding
);
private:
INetCfg *m_pINetCfg;
INetCfgLock *m_pLock;
}; // Class AppMyNetCfg
WBEMSTATUS
AppMyNetCfg::Initialize(
BOOL fWriteLock
)
{
HRESULT hr;
INetCfg *pnc = NULL;
INetCfgLock *pncl = NULL;
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
BOOL fLocked = FALSE;
BOOL fInitialized=FALSE;
if (m_pINetCfg != NULL || m_pLock != NULL)
{
ASSERT(FALSE);
goto end;
}
hr = CoCreateInstance( CLSID_CNetCfg,
NULL,
CLSCTX_SERVER,
IID_INetCfg,
(void **) &pnc);
if( !SUCCEEDED( hr ) )
{
// failure to create instance.
//TRACE_CRIT("ERROR: could not get interface to Net Config");
goto end;
}
//
// If require, get the write lock
//
if (fWriteLock)
{
WCHAR *szLockedBy = NULL;
hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
if( !SUCCEEDED( hr ) )
{
//TRACE_CRIT("ERROR: could not get interface to NetCfg Lock");
goto end;
}
hr = pncl->AcquireWriteLock( 1, // One Second
L"NLBManager",
&szLockedBy);
if( hr != S_OK )
{
//TRACE_CRIT("Could not get write lock. Lock held by %ws",
// (szLockedBy!=NULL) ? szLockedBy : L"<null>");
goto end;
}
}
// Initializes network configuration by loading into
// memory all basic networking information
//
hr = pnc->Initialize( NULL );
if( !SUCCEEDED( hr ) )
{
// failure to Initialize
//TRACE_CRIT("INetCfg::Initialize failure ");
goto end;
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
if (pncl!=NULL)
{
if (fLocked)
{
pncl->ReleaseWriteLock();
}
pncl->Release();
pncl=NULL;
}
if( pnc != NULL)
{
if (fInitialized)
{
pnc->Uninitialize();
}
pnc->Release();
pnc= NULL;
}
}
else
{
m_pINetCfg = pnc;
m_pLock = pncl;
}
return Status;
}
VOID
AppMyNetCfg::Deinitialize(
VOID
)
{
if (m_pLock!=NULL)
{
m_pLock->ReleaseWriteLock();
m_pLock->Release();
m_pLock=NULL;
}
if( m_pINetCfg != NULL)
{
m_pINetCfg->Uninitialize();
m_pINetCfg->Release();
m_pINetCfg= NULL;
}
}
WBEMSTATUS
AppMyNetCfg::GetNlbCompatibleNics(
OUT LPWSTR **ppszNics,
OUT UINT *pNumNics,
OUT UINT *pNumBoundToNlb // OPTIONAL
)
/*
Returns an array of pointers to string-version of GUIDS
that represent the set of alive and healthy NICS that are
suitable for NLB to bind to -- basically alive ethernet NICs.
Delete ppNics using the delete WCHAR[] operator. Do not
delete the individual strings.
*/
{
#define MY_GUID_LENGTH 38
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
HRESULT hr;
IEnumNetCfgComponent* pencc = NULL;
INetCfgComponent *pncc = NULL;
ULONG countToFetch = 1;
ULONG countFetched;
UINT NumNics = 0;
LPWSTR *pszNics = NULL;
INetCfgComponentBindings *pINlbBinding=NULL;
UINT NumNlbBoundNics = 0;
typedef struct _MYNICNODE MYNICNODE;
typedef struct _MYNICNODE
{
LPWSTR szNicGuid;
MYNICNODE *pNext;
} MYNICNODE;
MYNICNODE *pNicNodeList = NULL;
MYNICNODE *pNicNode = NULL;
*ppszNics = NULL;
*pNumNics = 0;
if (pNumBoundToNlb != NULL)
{
*pNumBoundToNlb = 0;
}
if (m_pINetCfg == NULL)
{
//
// This means we're not initialized
//
ASSERT(FALSE);
goto end;
}
hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
if( !SUCCEEDED( hr ) )
{
// failure to Enumerate net components
//TRACE_CRIT("%!FUNC! Could not enum netcfg adapters");
pencc = NULL;
goto end;
}
//
// Check if nlb is bound to the nlb component.
//
//
// If we need to count of NLB-bound nics, get instance of the nlb component
//
if (pNumBoundToNlb != NULL)
{
Status = GetBindingIF(L"ms_wlbs", &pINlbBinding);
if (FAILED(Status))
{
//TRACE_CRIT("%!FUNC! WARNING: NLB doesn't appear to be installed on this machine");
pINlbBinding = NULL;
}
}
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
{
LPWSTR szName = NULL;
hr = pncc->GetBindName( &szName );
if (!SUCCEEDED(hr))
{
//TRACE_CRIT("%!FUNC! WARNING: couldn't get bind name for 0x%p, ignoring",
// (PVOID) pncc);
continue;
}
do // while FALSE -- just to allow breaking out
{
UINT Len = wcslen(szName);
if (Len != MY_GUID_LENGTH)
{
//TRACE_CRIT("%!FUNC! WARNING: GUID %ws has unexpected length %ul",
// szName, Len);
break;
}
DWORD characteristics = 0;
hr = pncc->GetCharacteristics( &characteristics );
if(!SUCCEEDED(hr))
{
//TRACE_CRIT("%!FUNC! WARNING: couldn't get characteristics for %ws, ignoring",
// szName);
break;
}
if (((characteristics & NCF_PHYSICAL) || (characteristics & NCF_VIRTUAL)) && !(characteristics & NCF_HIDDEN))
{
ULONG devstat = 0;
// This is a physical or virtual miniport that is NOT hidden. These
// are the same adapters that show up in the "Network Connections"
// dialog. Hidden devices include WAN miniports, RAS miniports and
// NLB miniports - all of which should be excluded here.
// check if the nic is enabled, we are only
// interested in enabled nics.
//
hr = pncc->GetDeviceStatus( &devstat );
if(!SUCCEEDED(hr))
{
//TRACE_CRIT(
// "%!FUNC! WARNING: couldn't get dev status for %ws, ignoring",
// szName
// );
break;
}
// if any of the nics has any of the problem codes
// then it cannot be used.
if( devstat != CM_PROB_NOT_CONFIGURED
&&
devstat != CM_PROB_FAILED_START
&&
devstat != CM_PROB_NORMAL_CONFLICT
&&
devstat != CM_PROB_NEED_RESTART
&&
devstat != CM_PROB_REINSTALL
&&
devstat != CM_PROB_WILL_BE_REMOVED
&&
devstat != CM_PROB_DISABLED
&&
devstat != CM_PROB_FAILED_INSTALL
&&
devstat != CM_PROB_FAILED_ADD
)
{
//
// No problem with this nic and also
// physical device
// thus we want it.
//
if (pINlbBinding != NULL)
{
BOOL fBound = FALSE;
hr = pINlbBinding->IsBoundTo(pncc);
if( !SUCCEEDED( hr ) )
{
//TRACE_CRIT("IsBoundTo method failed for Nic %ws", szName);
goto end;
}
if( hr == S_OK )
{
//TRACE_VERB("BOUND: %ws\n", szName);
NumNlbBoundNics++;
fBound = TRUE;
}
else if (hr == S_FALSE )
{
//TRACE_VERB("NOT BOUND: %ws\n", szName);
fBound = FALSE;
}
}
// We allocate a little node to keep this string
// temporarily and add it to our list of nodes.
//
pNicNode = new MYNICNODE;
if (pNicNode == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
ZeroMemory(pNicNode, sizeof(*pNicNode));
pNicNode->szNicGuid = szName;
szName = NULL; // so we don't delete inside the lopp.
pNicNode->pNext = pNicNodeList;
pNicNodeList = pNicNode;
NumNics++;
}
else
{
// There is a problem...
//TRACE_CRIT(
// "%!FUNC! WARNING: Skipping %ws because DeviceStatus=0x%08lx",
// szName, devstat
// );
break;
}
}
else
{
//TRACE_VERB("%!FUNC! Ignoring non-physical device %ws", szName);
}
} while (FALSE);
if (szName != NULL)
{
CoTaskMemFree( szName );
}
pncc->Release();
pncc=NULL;
}
if (pINlbBinding!=NULL)
{
pINlbBinding->Release();
pINlbBinding = NULL;
}
if (NumNics==0)
{
Status = WBEM_NO_ERROR;
goto end;
}
//
// Now let's allocate space for all the nic strings and:w
// copy them over..
//
#define MY_GUID_LENGTH 38
pszNics = CfgUtilsAllocateStringArray(NumNics, MY_GUID_LENGTH);
if (pszNics == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
pNicNode= pNicNodeList;
for (UINT u=0; u<NumNics; u++, pNicNode=pNicNode->pNext)
{
ASSERT(pNicNode != NULL); // because we just counted NumNics of em.
UINT Len = wcslen(pNicNode->szNicGuid);
if (Len != MY_GUID_LENGTH)
{
//
// We should never get here beause we checked the length earlier.
//
//TRACE_CRIT("%!FUNC! ERROR: GUID %ws has unexpected length %ul",
// pNicNode->szNicGuid, Len);
ASSERT(FALSE);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
CopyMemory(
pszNics[u],
pNicNode->szNicGuid,
(MY_GUID_LENGTH+1)*sizeof(WCHAR));
ASSERT(pszNics[u][MY_GUID_LENGTH]==0);
}
Status = WBEM_NO_ERROR;
end:
//
// Now release the temporarly allocated memory.
//
pNicNode= pNicNodeList;
while (pNicNode!=NULL)
{
MYNICNODE *pTmp = pNicNode->pNext;
CoTaskMemFree(pNicNode->szNicGuid);
pNicNode->szNicGuid = NULL;
delete pNicNode;
pNicNode = pTmp;
}
if (FAILED(Status))
{
// TRACE_CRIT("%!FUNC! fails with status 0x%08lx", (UINT) Status);
NumNics = 0;
if (pszNics!=NULL)
{
delete pszNics;
pszNics = NULL;
}
}
else
{
if (pNumBoundToNlb != NULL)
{
*pNumBoundToNlb = NumNlbBoundNics;
}
*ppszNics = pszNics;
*pNumNics = NumNics;
}
if (pencc != NULL)
{
pencc->Release();
}
return Status;
}
WBEMSTATUS
AppMyNetCfg::GetBindingIF(
IN LPCWSTR szComponent,
OUT INetCfgComponentBindings **ppIBinding
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
INetCfgComponent *pncc = NULL;
INetCfgComponentBindings *pnccb = NULL;
HRESULT hr;
if (m_pINetCfg == NULL)
{
//
// This means we're not initialized
//
ASSERT(FALSE);
goto end;
}
hr = m_pINetCfg->FindComponent(szComponent, &pncc);
if (FAILED(hr))
{
// TRACE_CRIT("Error checking if component %ws does not exist\n", szComponent);
pncc = NULL;
goto end;
}
else if (hr == S_FALSE)
{
Status = WBEM_E_NOT_FOUND;
// TRACE_CRIT("Component %ws does not exist\n", szComponent);
goto end;
}
hr = pncc->QueryInterface( IID_INetCfgComponentBindings, (void **) &pnccb );
if( !SUCCEEDED( hr ) )
{
// TRACE_CRIT("INetCfgComponent::QueryInterface failed ");
pnccb = NULL;
goto end;
}
Status = WBEM_NO_ERROR;
end:
if (pncc)
{
pncc->Release();
pncc=NULL;
}
*ppIBinding = pnccb;
return Status;
}
BOOL NoAdminNics(void)
/*
Return TRUE IFF all NICs on this machine are bound to NLB.
*/
{
LPWSTR *pszNics = NULL;
OUT UINT NumNics = 0;
OUT UINT NumBoundToNlb = 0;
WBEMSTATUS Status = WBEM_NO_ERROR;
BOOL fNetCfgInitialized = FALSE;
AppMyNetCfg NetCfg;
BOOL fRet = FALSE;
//
// Get and initialize interface to netcfg
//
Status = NetCfg.Initialize(FALSE); // TRUE == get write lock.
if (FAILED(Status))
{
goto end;
}
fNetCfgInitialized = TRUE;
//
// Get the total list of enabled nics and the list of nics
// bound to NLB. If there are non-zero enabled nics and all are
// bound to NLB, we return TRUE.
//
Status = NetCfg.GetNlbCompatibleNics(
&pszNics,
&NumNics,
&NumBoundToNlb
);
if (!FAILED(Status))
{
fRet = NumNics && (NumNics == NumBoundToNlb);
if (NumNics)
{
delete pszNics;
pszNics = NULL;
}
}
end:
if (fNetCfgInitialized)
{
NetCfg.Deinitialize();
}
return fRet;
}
void
Application::ProcessMsgQueue()
{
MSG msg;
BOOL bDoingBackgroundProcessing = FALSE;
TRACE_INFO(L"-> %!FUNC!");
if (!mfn_IsMainThread()) goto end;
if (InterlockedIncrement(&m_lMsgProcReentrancyCount) > 1)
{
InterlockedDecrement(&m_lMsgProcReentrancyCount);
goto end;
}
while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
#if BUGFIX334243
if (msg.message == MYWM_DEFER_UI_MSG)
{
// DummyAction(L"Hey -- got DEFER_UI_MSG ProcessMsgQueue!");
}
#endif // BUGFIX334243
if ( !this->PumpMessage( ) )
{
bDoingBackgroundProcessing = FALSE;
::PostQuitMessage(0);
break;
}
}
// let MFC do its idle processing
LONG lIdle = 0;
while ( this->OnIdle(lIdle++ ) )
{
}
// Perform some background processing here
// using another call to OnIdle
this->DoWaitCursor(0); // process_msgqueue() breaks the hour glass cursor, This call restores the hour glass cursor if there was one
InterlockedDecrement(&m_lMsgProcReentrancyCount);
if (m_fQuit)
{
::PostQuitMessage(0);
}
end:
TRACE_INFO(L"<- %!FUNC!");
return;
}
//
// Get application-wide lock. If main thread, while waiting to get the lock,
// periodically process the msg loop.
//
VOID
Application::Lock()
{
//
// See notes.txt entry
// 01/23/2002 JosephJ DEADLOCK in Leftview::mfn_Lock
// for the reason for this convoluted implementation of mfn_Lock
//
if (mfn_IsMainThread())
{
EnterCriticalSection(&m_crit);
}
else
{
while (!TryEnterCriticalSection(&m_crit))
{
this->ProcessMsgQueue();
Sleep(100);
}
}
}
//
// Get application-wide unlock
//
VOID
Application::Unlock()
{
LeaveCriticalSection(&m_crit);
}