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.
 
 
 
 
 
 

1469 lines
42 KiB

//***************************************************************************
//
// CONNECT.CPP
//
// Module: NLB Manager
//
// Purpose: Implements ConnectDialog, which is a dialog for connecting
// to a host, extracting and displaying its list of adapters.
//
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
//
// History:
//
// 07/30/01 JosephJ Created
//
//***************************************************************************
#include "precomp.h"
#pragma hdrstop
#include "private.h"
#include "connect.h"
#include "connect.tmh"
// BEGIN_MESSAGE_MAP( ConnectDialog, CDialog )
BEGIN_MESSAGE_MAP( ConnectDialog, CPropertyPage )
ON_BN_CLICKED(IDC_BUTTON_CONNECT, OnButtonConnect)
ON_WM_HELPINFO()
ON_WM_CONTEXTMENU()
ON_NOTIFY( LVN_ITEMCHANGED, IDC_LIST_INTERFACES, OnSelchanged )
ON_EN_UPDATE(IDC_EDIT_HOSTADDRESS,OnUpdateEditHostAddress)
//
// Other options...
//
// ON_EN_SETFOCUS(IDC_EDIT_HOSTADDRESS,OnSetFocusEditHostAddress)
// ON_WM_ACTIVATE()
// ON_NOTIFY( NM_DBLCLK, IDC_LIST_INTERFACES, OnDoubleClick )
// ON_NOTIFY( LVN_COLUMNCLICK, IDC_LIST_INTERFACES, OnColumnClick )
//
END_MESSAGE_MAP()
//
// Static help-id maps
//
DWORD
ConnectDialog::s_HelpIDs[] =
{
IDC_TEXT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS,
IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS,
IDC_BUTTON_CONNECT, IDC_BUTTON_CONNECT,
IDC_GROUP_CONNECTION_STATUS, IDC_GROUP_CONNECTION_STATUS,
IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS,
IDC_TEXT_INTERFACES, IDC_LIST_INTERFACES,
IDC_LIST_INTERFACES, IDC_LIST_INTERFACES,
0, 0
};
DWORD
ConnectDialog::s_ExistingClusterHelpIDs[] =
{
IDC_TEXT_HOSTADDRESS, IDC_EDIT_HOSTADDRESSEX,
IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESSEX,
IDC_BUTTON_CONNECT, IDC_BUTTON_CONNECTEX,
IDC_GROUP_CONNECTION_STATUS, IDC_GROUP_CONNECTION_STATUS,
IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS,
IDC_TEXT_INTERFACES, IDC_LIST_INTERFACESEX,
IDC_LIST_INTERFACES, IDC_LIST_INTERFACESEX,
0, 0
};
VOID zap_slash(LPWSTR sz) // Look for a the first '/' and set it to zero.
{
sz = wcschr(sz, '/');
if (sz!=NULL) *sz=0;
}
ConnectDialog::ConnectDialog(
CPropertySheet *psh,
Document *pDocument,
NLB_EXTENDED_CLUSTER_CONFIGURATION *pNlbCfg,
ENGINEHANDLE *pehInterface, // IN OUT
DlgType type,
CWnd* parent
)
:
// CDialog( IDD, parent )
CPropertyPage(IDD),
m_type(type),
m_fOK(FALSE),
m_pshOwner(psh),
m_pDocument(pDocument),
m_fInterfaceSelected(FALSE),
m_iInterfaceListItem(0),
m_pehSelectedInterfaceId(pehInterface),
m_fSelectedInterfaceIsInCluster(FALSE),
m_pNlbCfg(pNlbCfg),
m_ehHostId(NULL)
{
*m_pehSelectedInterfaceId = NULL;
}
void
ConnectDialog::DoDataExchange( CDataExchange* pDX )
{
// CDialog::DoDataExchange(pDX);
CPropertyPage::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST_INTERFACES, interfaceList);
DDX_Control(pDX, IDC_TEXT_CONNECTION_STATUS, connectionStatus);
DDX_Control(pDX, IDC_TEXT_INTERFACES, listHeading);
DDX_Control(pDX, IDC_EDIT_HOSTADDRESS, hostAddress);
//
// Note: the buttons are handled by the ON_BN_CLICKED macro
// above.
//
// DDX_Control(pDX, IDC_BUTTON_CONNECT, buttonConnect);
// DDX_Control(pDX, IDC_BUTTON_CREDENTIALS, credentialsButton);
}
BOOL
ConnectDialog::OnInitDialog()
{
// BOOL fRet = CDialog::OnInitDialog();
BOOL fRet = CPropertyPage::OnInitDialog();
_bstr_t bstrDescription;
_bstr_t bstrListText;
m_fOK = FALSE;
switch(m_type)
{
case DLGTYPE_NEW_CLUSTER:
bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_NEW_HINT);
bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_NEW_LIST_TXT);
break;
case DLGTYPE_EXISTING_CLUSTER:
bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_EXISTING_HINT);
bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_EXISTING_LIST_TXT);
break;
case DLGTYPE_ADD_HOST:
bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_ADD_HOST_HINT);
bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_ADD_HOST_LIST_TXT);
break;
}
//
// Initialize the caption and discription based on the type of
// dialog.
//
{
CWnd *pItem = GetDlgItem(IDC_TEXT_CONNECT_DESCRIPTION);
pItem->SetWindowText(bstrDescription);
pItem = GetDlgItem(IDC_TEXT_INTERFACES);
pItem->SetWindowText(bstrListText);
}
// Initialize the list control
mfn_InitializeListView();
// interfaceList.SetCurSel( 0 );
// ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_HOSTADDRESS), TRUE );
// ::EnableWindow(::GetDlgItem(m_hWnd, IDC_LIST_INTERFACES), TRUE );
//
// The "Connect" button starts out disabled. It is only enabled
// when the uers types non-whitespace text in the host address
// edit control.
//
::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, FALSE);
return fRet;
}
BOOL
ConnectDialog::OnHelpInfo (HELPINFO* helpInfo )
{
if( helpInfo->iContextType == HELPINFO_WINDOW )
{
//
// We choose the context-senstive map appropriate to the
// type of dialog (m_type).
//
ULONG_PTR pHelpIds = (ULONG_PTR) s_HelpIDs;
BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER);
if (fExisting)
{
pHelpIds = (ULONG_PTR) s_ExistingClusterHelpIDs;
}
::WinHelp( static_cast<HWND> ( helpInfo->hItemHandle ),
CVY_CTXT_HELP_FILE,
HELP_WM_HELP,
(ULONG_PTR ) pHelpIds);
}
return TRUE;
}
void
ConnectDialog::OnContextMenu( CWnd* pWnd, CPoint point )
{
::WinHelp( m_hWnd,
CVY_CTXT_HELP_FILE,
HELP_CONTEXTMENU,
(ULONG_PTR ) s_HelpIDs);
}
void
ConnectDialog::mfn_InitializeListView(void)
//
// Set the columns on the list box based on the type of dialog
//
{
BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER);
RECT rect;
INT colWidth;
interfaceList.GetClientRect(&rect);
colWidth = (rect.right - rect.left)/4;
if (fExisting)
{
//
// The interface list is that of interfaces already bound to NLB.
// we display the cluster dnsname and ip first, then adapter name.
//
interfaceList.InsertColumn(
0,
GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERNAME),
LVCFMT_LEFT,
colWidth);
interfaceList.InsertColumn(
1,
GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERIP),
LVCFMT_LEFT,
colWidth);
interfaceList.InsertColumn(
2,
GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFNAME),
LVCFMT_LEFT,
colWidth * 2);
}
else
{
//
// The interface list is that of interfaces NOT bound to NLB.
// We display the current IP address first, then adapter name.
//
interfaceList.InsertColumn(
0,
GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFNAME),
LVCFMT_LEFT,
colWidth * 2);
interfaceList.InsertColumn(
1,
GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFIP),
LVCFMT_LEFT,
colWidth);
interfaceList.InsertColumn(
2,
GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERIP),
LVCFMT_LEFT,
colWidth);
}
//
// Allow entire row to be selected.
//
interfaceList.SetExtendedStyle(
interfaceList.GetExtendedStyle() | LVS_EX_FULLROWSELECT );
}
void
ConnectDialog::mfn_InsertBoundInterface(
ENGINEHANDLE ehInterfaceId,
LPCWSTR szClusterName,
LPCWSTR szClusterIp,
LPCWSTR szInterfaceName
)
{
if (szClusterName == NULL)
{
szClusterName = L"";
}
if (szClusterIp == NULL)
{
szClusterIp = L"";
}
if (szInterfaceName == NULL)
{
szInterfaceName = L""; // TODO: localize
}
int iRet = interfaceList.InsertItem(
LVIF_TEXT | LVIF_PARAM, // nMask
0, // nItem,
szClusterName, // lpszItem
0, // nState (unused)
0, // nStateMask (unused)
0, // nImage (unused)
(LPARAM) ehInterfaceId // lParam
);
// interfaceList.InsertItem(0, szClusterName);
interfaceList.SetItem(
0, // nItem
1,// nSubItem
LVIF_TEXT, // nMask
szClusterIp, // lpszItem
0, // nImage
0, // nState
0, // nStateMask
0 // lParam
);
interfaceList.SetItem(
0, // nItem
2,// nSubItem
LVIF_TEXT, // nMask
szInterfaceName, // lpszItem
0, // nImage
0, // nState
0, // nStateMask
0 // lParam
);
}
void
ConnectDialog::mfn_InsertInterface(
ENGINEHANDLE ehInterfaceId,
LPCWSTR szInterfaceIp,
LPCWSTR szInterfaceName,
LPCWSTR szClusterIp
)
{
if (szInterfaceIp == NULL)
{
szInterfaceIp = L"";
}
if (szInterfaceName == NULL)
{
szInterfaceName = L""; // TODO: localize
}
if (szClusterIp == NULL)
{
szClusterIp = L"";
}
int iRet = interfaceList.InsertItem(
LVIF_TEXT | LVIF_PARAM, // nMask
0, // nItem,
szInterfaceName, // lpszItem
0, // nState (unused)
0, // nStateMask (unused)
0, // nImage (unused)
(LPARAM) ehInterfaceId // lParam
);
// interfaceList.InsertItem(0, szInterfaceIp);
interfaceList.SetItem(
0, // nItem
1,// nSubItem
LVIF_TEXT, // nMask
szInterfaceIp, // lpszItem
0, // nImage
0, // nState
0, // nStateMask
0 // lParam
);
// interfaceList.InsertItem(0, szInterfaceIp);
interfaceList.SetItem(
0, // nItem
2,// nSubItem
LVIF_TEXT, // nMask
szClusterIp, // lpszItem
0, // nImage
0, // nState
0, // nStateMask
0 // lParam
);
// interfaceList.SetCurSel( 0 );
}
void ConnectDialog::OnOK()
{
// CDialog::OnOK();
CPropertyPage::OnOK();
}
_bstr_t g_hostName;
void ConnectDialog::OnButtonConnect()
/*
User has clicked the "Connect" button.
1. (For now) If empty string, do nothing. Later we'll disable/enable.
2. Switch cursor to hourglass, connect, switch back from hourglass.
*/
{
BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER);
BOOL fRet;
#define MAX_HOST_ADDRESS_LENGTH 256
WCHAR szHostAddress[MAX_HOST_ADDRESS_LENGTH+1];
ENGINEHANDLE ehHostId;
CHostSpec hSpec;
BOOL fNicsAvailable = FALSE;
NLBERROR err;
_bstr_t bstrUserName;
_bstr_t bstrPassword;
_bstr_t bstrConnectionStatus;
//
// Get the connection string. If empty, we simply return.
//
{
fRet = GetDlgItemText(
IDC_EDIT_HOSTADDRESS,
szHostAddress,
MAX_HOST_ADDRESS_LENGTH
);
if (!fRet)
{
goto end;
}
//
// Clean out trailing whitespace..
//
{
LPWSTR sz = (szHostAddress+wcslen(szHostAddress))-1;
while (sz >= szHostAddress)
{
WCHAR c = *sz;
if (c == ' ' || c == '\t')
{
*sz = 0;
}
else
{
break;
}
sz--;
}
}
if (szHostAddress[0] == 0)
{
goto end;
}
}
//
// Let's see if we have any record of this connection string -- if so
// we use that record's username and password as the first guest.
//
err = gEngine.LookupConnectionInfo(
szHostAddress,
REF bstrUserName,
REF bstrPassword
);
if (NLBFAILED(err))
{
//
// Nope -- let's use default credentials...
//
m_pDocument->getDefaultCredentials(REF bstrUserName, REF bstrPassword);
}
//
// Set status
//
{
bstrConnectionStatus = GETRESOURCEIDSTRING(IDS_CONNECT_STATUS_CONNECTING);
SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, (LPCWSTR) bstrConnectionStatus);
}
//
// Clear the list of interfaces.
//
interfaceList.DeleteAllItems();
//
// These two buffers must be defined outside the loop below because
// ConnInfo points to them across multiple iterations.
// We initialize them to the user-name and password we obtained above...
//
WCHAR rgUserName[CREDUI_MAX_USERNAME_LENGTH+1];
WCHAR rgPassword[MAX_ENCRYPTED_PASSWORD_LENGTH];
LPCWSTR szName = (LPCWSTR) bstrUserName;
LPCWSTR szPassword = (LPCWSTR) bstrPassword;
if (szName == NULL)
{
szName = L"";
}
if (szPassword == NULL)
{
szPassword = L"";
}
ARRAYSTRCPY(rgUserName, szName);
ARRAYSTRCPY(rgPassword, szPassword);
while (1)
{
WMI_CONNECTION_INFO ConnInfo;
CLocalLogger logger;
ZeroMemory(&ConnInfo, sizeof(ConnInfo));
ConnInfo.szMachine = szHostAddress;
if (*rgUserName == 0)
{
// Use default creds ...
ConnInfo.szUserName = NULL;
ConnInfo.szPassword = NULL;
}
else
{
ConnInfo.szUserName = rgUserName;
ConnInfo.szPassword = rgPassword;
}
//
// ACTUALLY CONNECT TO THE HOST
//
BeginWaitCursor();
// TRUE 2nd param says overwrite the connection info for this host
// if the connect succeeds.
err = gEngine.ConnectToHost(&ConnInfo, TRUE, REF ehHostId, REF bstrConnectionStatus);
EndWaitCursor();
if (err != NLBERR_ACCESS_DENIED)
{
break;
}
//
// We got an access-denied --
// Bring ui UI prompting for new username and password.
//
_bstr_t bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_CONNECT);
logger.Log(IDS_SPECIFY_MACHINE_CREDS, ConnInfo.szMachine);
fRet = PromptForEncryptedCreds(
m_hWnd,
(LPCWSTR) bstrCaption,
logger.GetStringSafe(),
rgUserName,
ASIZE(rgUserName),
rgPassword,
ASIZE(rgPassword)
);
if (!fRet)
{
err = NLBERR_CANCELLED;
break;
}
} // while (1)
if (err == NLBERR_OK)
{
//
// Set status
//
bstrConnectionStatus = GETRESOURCEIDSTRING(IDS_CONNECT_STATUS_CONNECTED);
SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, (LPCWSTR) bstrConnectionStatus);
//
// Clear list of all items
//
interfaceList.DeleteAllItems();
err = gEngine.GetHostSpec(ehHostId, REF hSpec);
if (NLBFAILED(err))
{
goto end;
}
//
// Extract list of interfaces
//
for( int i = 0; i < hSpec.m_ehInterfaceIdList.size(); ++i )
{
ENGINEHANDLE ehIID = hSpec.m_ehInterfaceIdList[i];
CInterfaceSpec iSpec;
err = gEngine.GetInterfaceSpec(ehIID, REF iSpec);
if (err == NLBERR_OK)
{
//
// Get interfaces.
//
// szFriendlyName
// szClusterIp (NULL if nlb not bound)
// szClusterName (NULL if nlb not bound)
// szFirstIp (first ip bound to NLB)
//
WBEMSTATUS wStat;
LPWSTR szFriendlyName = NULL;
LPWSTR szClusterIp = NULL;
LPWSTR szClusterName = NULL;
LPWSTR *pszNetworkAddresses = NULL;
BOOL fNlbBound = FALSE;
UINT NumAddresses=0;
LPWSTR szFirstNetworkAddress = NULL;
wStat = iSpec.m_NlbCfg.GetFriendlyName(&szFriendlyName);
if (FAILED(wStat)) szFriendlyName = NULL;
wStat = iSpec.m_NlbCfg.GetNetworkAddresses(
&pszNetworkAddresses,
&NumAddresses
);
if (FAILED(wStat))
{
pszNetworkAddresses = NULL;
NumAddresses = 0;
}
else if (NumAddresses != 0)
{
szFirstNetworkAddress = pszNetworkAddresses[0];
zap_slash(szFirstNetworkAddress); // zap the /
}
if (iSpec.m_NlbCfg.IsNlbBound())
{
fNlbBound = TRUE;
if (iSpec.m_NlbCfg.IsValidNlbConfig())
{
wStat = iSpec.m_NlbCfg.GetClusterNetworkAddress(
&szClusterIp
);
if (FAILED(wStat))
{
szClusterIp = NULL;
}
else if (szClusterIp!=NULL)
{
zap_slash(szClusterIp);
}
wStat = iSpec.m_NlbCfg.GetClusterName(
&szClusterName
);
if (FAILED(wStat))
{
szClusterName = NULL;
}
}
}
if (fExisting && fNlbBound)
{
fNicsAvailable = TRUE;
mfn_InsertBoundInterface(
ehIID,
szClusterName,
szClusterIp,
szFriendlyName
);
}
else if (!fExisting)
{
fNicsAvailable = TRUE;
mfn_InsertInterface(
ehIID,
szFirstNetworkAddress,
szFriendlyName,
szClusterIp
);
}
delete szFriendlyName;
delete szClusterIp;
delete szClusterName;
delete pszNetworkAddresses;
}
}
if (!fNicsAvailable)
{
//
// There are no NICs on this host on which NLB may be installed.
//
if (fExisting)
{
MessageBox(
GETRESOURCEIDSTRING( IDS_CONNECT_NO_NICS_EXISTING_CLUSTER),
GETRESOURCEIDSTRING( IDS_CONNECT_SELECT_NICS_ERROR ),
MB_ICONSTOP | MB_OK
);
}
else
{
MessageBox(
GETRESOURCEIDSTRING( IDS_CONNECT_NO_NICS_NEW_CLUSTER ),
GETRESOURCEIDSTRING( IDS_CONNECT_SELECT_NICS_ERROR ),
MB_ICONSTOP | MB_OK
);
}
}
else
{
m_ehHostId = ehHostId;
m_MachineName = hSpec.m_MachineName; // machine name.
m_fInterfaceSelected = FALSE;
m_iInterfaceListItem = 0;
*m_pehSelectedInterfaceId = NULL;
m_fSelectedInterfaceIsInCluster = FALSE;
if (fExisting)
{
//
// We're asked to pick an existing cluster.
// Let's select the first interface bound to NLB
//
mfn_SelectInterfaceIfAlreadyInCluster(
NULL
);
}
else
{
//
// We're asked to add a host to a cluster.
//
// Now we check if an interfaces is already part of
// the cluster. If so we select it and prevent the user from
// subsequently changing this selection. Furthermore, we use
// the host-specific settings that already exist on that
// interface.
//
mfn_SelectInterfaceIfAlreadyInCluster(
m_pNlbCfg->NlbParams.cl_ip_addr
);
//
// Let's apply the selected interface's information.
//
mfn_ApplySelectedInterfaceConfiguration();
}
}
}
else
{
//
// Error connecting.
//
LPCWSTR szErr = (LPCWSTR)bstrConnectionStatus;
if (szErr == NULL)
{
szErr = L"";
}
SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, szErr);
}
end:
return;
}
void ConnectDialog::OnSelchanged(NMHDR * pNotifyStruct, LRESULT * result )
/*
A listbox item has been selected.
*/
{
POSITION pos = interfaceList.GetFirstSelectedItemPosition();
UINT WizardFlags = 0;
int index = -1;
if( pos != NULL )
{
index = interfaceList.GetNextSelectedItem( pos );
}
if (m_type == DLGTYPE_NEW_CLUSTER)
{
//
// We're not the first, so we enable the back button.
//
WizardFlags = PSWIZB_BACK;
}
if (m_fInterfaceSelected && index == m_iInterfaceListItem)
{
//
// No change in selection; Nothing to do..
// In fact we do NOT want to change the settings because the user
// may have made some host-specific changes like change the
// dedicated IP.
//
goto end;
}
if (m_fSelectedInterfaceIsInCluster)
{
BOOL fRet = FALSE;
//
// we don't allow a change in selection -- move back to
// selecting the cluster ip.
fRet = interfaceList.SetItemState(
m_iInterfaceListItem,
LVIS_FOCUSED | LVIS_SELECTED, // nState
LVIS_FOCUSED | LVIS_SELECTED // nMask
);
if (fRet)
{
goto end;
}
}
//
// We are getting here ONLY if (a) there has been a change in the selection
// and (b) the selected interface is NOT already in the cluster.
// We'll set the dedicated ip and subnet mask to be the first
// address/subnet bound to the adapter.
//
// If adapter is configured for DHCP, we leave the dedicated IP field
// blank.
//
if (index != -1)
{
//
// Update m_pNlbCfg appropriately...
//
ENGINEHANDLE ehIID = NULL;
ehIID = (ENGINEHANDLE) interfaceList.GetItemData(index);
if (ehIID == NULL)
{
TRACE_CRIT("%!FUNC! could not get ehIID for index %lu", index);
goto end;
}
else
{
//
// Update the saved-away "selected interface" ID.
//
ENGINEHANDLE ehOldId = *m_pehSelectedInterfaceId;
*m_pehSelectedInterfaceId = ehIID;
m_fInterfaceSelected = TRUE;
m_iInterfaceListItem = index;
//
// TODO: duplicate code
//
CInterfaceSpec iSpec;
WBEMSTATUS wStat;
LPWSTR szFriendlyName = NULL;
LPWSTR szClusterIp = NULL;
LPWSTR szClusterName = NULL;
LPWSTR *pszNetworkAddresses = NULL;
UINT NumAddresses=0;
LPWSTR szFirstNetworkAddress = NULL;
NLBERROR err;
err = gEngine.GetInterfaceSpec(ehIID, REF iSpec);
if (!NLBOK(err))
{
TRACE_CRIT("%!FUNC! could not get iSpec for ehSpec 0x%lx", ehIID);
goto end;
}
wStat = iSpec.m_NlbCfg.GetFriendlyName(&szFriendlyName);
if (FAILED(wStat)) szFriendlyName = NULL;
wStat = iSpec.m_NlbCfg.GetNetworkAddresses(
&pszNetworkAddresses,
&NumAddresses
);
if (FAILED(wStat))
{
pszNetworkAddresses = NULL;
NumAddresses = 0;
}
else if (NumAddresses != 0)
{
szFirstNetworkAddress = pszNetworkAddresses[0];
}
m_pNlbCfg->SetFriendlyName(szFriendlyName);
if (iSpec.m_NlbCfg.IsNlbBound())
{
if (m_type != DLGTYPE_EXISTING_CLUSTER)
{
//
// The user has selected an interface that is bound with
// some other IP address -- we should put up a message box
// here or maybe later, on kill-active.
//
}
}
//
// Set defaults for dedicatedip -- the first network address on
// the NIC, but ONLY if this address is not a cluster IP address.
//
if (szFirstNetworkAddress != NULL)
{
LPCWSTR szAddress = szFirstNetworkAddress;
WCHAR rgIp[WLBS_MAX_CL_IP_ADDR+1];
LPCWSTR pSlash = wcsrchr(szAddress, (int) '/');
if (pSlash != NULL)
{
UINT len = (UINT) (pSlash - szAddress);
if (len < WLBS_MAX_CL_IP_ADDR)
{
CopyMemory(rgIp, szAddress, len*sizeof(WCHAR));
rgIp[len] = 0;
szAddress = rgIp;
}
}
if (!_wcsicmp(m_pNlbCfg->NlbParams.cl_ip_addr, szAddress))
{
szFirstNetworkAddress = NULL;
}
if (iSpec.m_NlbCfg.fDHCP)
{
//
// The adapter is currently under DHCP control. We don't
// want to suggest that we use the current IP address
// as the static DIP!
//
szFirstNetworkAddress = NULL;
}
//
// TODO -- check also if this address conflicts with the
// additional VIPS.
//
}
m_pNlbCfg->SetDedicatedNetworkAddress(szFirstNetworkAddress); // NULL ok
delete szFriendlyName;
delete szClusterIp;
delete szClusterName;
delete pszNetworkAddresses;
}
if (m_type == DLGTYPE_EXISTING_CLUSTER)
{
// we're last page, so enable finish.
WizardFlags |= PSWIZB_FINISH;
}
else
{
// we're not the last page, so enable next.
WizardFlags |= PSWIZB_NEXT;
}
}
m_pshOwner->SetWizardButtons(WizardFlags);
end:
return;
}
BOOL
ConnectDialog::OnSetActive()
{
BOOL fRet = CPropertyPage::OnSetActive();
if (fRet)
{
UINT WizardFlags = 0;
if (m_type == DLGTYPE_NEW_CLUSTER)
{
WizardFlags |= PSWIZB_BACK; // we're not the first page.
}
if (m_fInterfaceSelected)
{
WizardFlags |= PSWIZB_NEXT; // Ok to continue.
}
m_pshOwner->SetWizardButtons(WizardFlags);
}
return fRet;
}
LRESULT ConnectDialog::OnWizardNext()
{
LRESULT lRet = 0;
TRACE_INFO("%!FUNC! ->");
lRet = CPropertyPage::OnWizardNext();
if (lRet != 0)
{
goto end;
}
if (mfn_ValidateData())
{
lRet = 0;
}
else
{
lRet = -1; // validation failed -- stay in current page.
}
end:
TRACE_INFO("%!FUNC! <- returns %lu", lRet);
return lRet;
}
void ConnectDialog::OnUpdateEditHostAddress()
{
//
// This gets called when the user has made changes to the connect-to-host
// edit control.
//
//
// We get the latest text -- if null or just blanks, we
// disable the connect window.
// Else we enable the connect window.
//
#define BUF_SIZ 32
WCHAR rgBuf[BUF_SIZ+1];
int l = hostAddress.GetWindowText(rgBuf, BUF_SIZ);
if (l == 0 || _wcsspnp(rgBuf, L" \t")==NULL)
{
//
// Empty string or entirely whitespace.
//
::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, FALSE);
}
else
{
//
// Non-empty string -- enable button and make it the default.
//
::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, TRUE);
this->SetDefID(IDC_BUTTON_CONNECT);
}
}
void
ConnectDialog::mfn_SelectInterfaceIfAlreadyInCluster(LPCWSTR szClusterIp)
/*
Check the list of interfaces to see if there exists an interface
which is is already part of the cluster -- i.e., it is bound and it's
cluster ip matches the one in m_pNlbCfg.
If so, we select it, and furthermore, prevent the user from selecting
any other interface.
*/
{
ENGINEHANDLE ehInterfaceId = NULL;
NLBERROR nerr;
UINT NumFound = 0;
nerr = gEngine.FindInterfaceOnHostByClusterIp(
m_ehHostId,
//m_pNlbCfg->NlbParams.cl_ip_addr,
szClusterIp,
REF ehInterfaceId,
REF NumFound
);
if (!NLBOK(nerr))
{
// not found or bad host id or some other err -- we don't care which.
goto end;
}
//
// Find the list item with this ehInterfaceId.
//
{
LVFINDINFO Info;
int nItem;
ZeroMemory(&Info, sizeof(Info));
Info.flags = LVFI_PARAM;
Info.lParam = ehInterfaceId;
nItem = interfaceList.FindItem(&Info);
if (nItem != -1)
{
BOOL fRet;
UINT WizardFlags = 0;
//
// Found it! -- select it and use it's host-specific information
//
m_fInterfaceSelected = TRUE;
m_iInterfaceListItem = nItem;
*m_pehSelectedInterfaceId = ehInterfaceId;
if (NumFound == 1)
{
m_fSelectedInterfaceIsInCluster = TRUE;
}
fRet = interfaceList.SetItemState(
nItem,
LVIS_FOCUSED | LVIS_SELECTED, // nState
LVIS_FOCUSED | LVIS_SELECTED // nMask
);
if (m_type == DLGTYPE_NEW_CLUSTER)
{
WizardFlags |= PSWIZB_BACK; // we're not the first page.
}
if (m_type == DLGTYPE_EXISTING_CLUSTER)
{
WizardFlags |= PSWIZB_FINISH;
}
else
{
WizardFlags |= PSWIZB_NEXT;
}
// TODO: consider adding finish in add-host case here.
m_pshOwner->SetWizardButtons(WizardFlags);
}
}
//
// Go through and set all other list items to have a gray background.
//
end:
return;
}
void
ConnectDialog::mfn_ApplySelectedInterfaceConfiguration(void)
{
ENGINEHANDLE ehIID = *m_pehSelectedInterfaceId;
CInterfaceSpec iSpec;
WBEMSTATUS wStat;
BOOL fNlbBound = FALSE;
NLBERROR err;
NLB_EXTENDED_CLUSTER_CONFIGURATION TmpConfig;
if (!m_fSelectedInterfaceIsInCluster) goto end;
err = gEngine.GetInterfaceSpec(ehIID, REF iSpec);
if (!NLBOK(err))
{
TRACE_CRIT("%!FUNC! could not get iSpec for ehSpec 0x%lx", ehIID);
goto end;
}
if (!iSpec.m_NlbCfg.IsValidNlbConfig())
{
// can't trust NLB config info on this interface.
goto end;
}
//
// We'll make a copy of the interface's config and apply the cluster
// properties to it and then copy this copy over to the cluster properties.
//
wStat = TmpConfig.Update(&iSpec.m_NlbCfg);
if (FAILED(wStat))
{
TRACE_CRIT("%!FUNC! could not perform an internal copy!");
goto end;
}
err = gEngine.ApplyClusterWideConfiguration(REF *m_pNlbCfg, TmpConfig);
if (!NLBOK(err))
{
goto end;
}
wStat = m_pNlbCfg->Update(&TmpConfig);
if (FAILED(wStat))
{
goto end;
}
// Fall through.
end:
return;
}
BOOL
ConnectDialog::mfn_ValidateData()
/*
Make sure the interface is not already part of a different cluster,
or other problem (eg we're connnecting to this interface and it's DHCP)
NewCluster:
ExistingCluster:
AddHost:
In all cases, we fail if pISpec already has an ehCluster associated with
it. Put up a message box with the associated ehCluster.
*/
{
BOOL fRet = FALSE;
NLBERROR nerr;
ENGINEHANDLE ehHost = NULL;
ENGINEHANDLE ehCluster = NULL;
_bstr_t bstrFriendlyName;
_bstr_t bstrDisplayName;
_bstr_t bstrHostName;
LPCWSTR szFriendlyName = NULL;
BOOL fOkCancel=FALSE;
CLocalLogger msgLog;
_bstr_t bstrCaption;
if (*m_pehSelectedInterfaceId == NULL)
{
//
// We shouldn't get here because the "Next" button is only enabled
// if there IS a selection; however we deal with this case anyway.
//
// bstrCaption = L"No interface selected";
bstrCaption = GETRESOURCEIDSTRING (IDS_CONNECT_NO_INTERFACE_SELECTED);
msgLog.Log(IDS_CONNECT_SELECT_AN_INTERFACE);
goto end;
}
nerr = gEngine.GetInterfaceIdentification(
*m_pehSelectedInterfaceId,
REF ehHost,
REF ehCluster,
REF bstrFriendlyName,
REF bstrDisplayName,
REF bstrHostName
);
if (NLBFAILED(nerr))
{
//
// This indicates an internal error like a bad handle.
//
bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
// szCaption = L"Unable to proceed";
msgLog.Log(IDS_CONNECT_UNABLE_TO_PROCEEED_INTERNAL);
// szMessage = L"Unable to proceed due to an internal error.";
goto end;
}
szFriendlyName = (LPCWSTR) bstrFriendlyName;
if (szFriendlyName == NULL)
{
szFriendlyName = L"";
}
if (ehCluster == NULL)
{
//
// Should be good to go.
// TODO -- if interface already bound AND m_type is NOT
// DLGTYPE_EXISTING_CLUSTER, we should ask if user wants to
// clobber the existing interface.
//
if (m_type != DLGTYPE_EXISTING_CLUSTER)
{
CInterfaceSpec iSpec;
nerr = gEngine.GetInterfaceSpec(*m_pehSelectedInterfaceId, REF iSpec);
if (nerr == NLBERR_OK)
{
//
// Check if we're connected to this NIC, and
// the NIC is DHCP, so we're not going to be able to
// keep the connected IP address.
//
// If so, we cannot proceed.
//
{
ENGINEHANDLE ehConnectionIF = NULL;
_bstr_t bstrConnectionString;
UINT uConnectionIp = 0;
nerr = gEngine.GetHostConnectionInformation(
ehHost,
REF ehConnectionIF,
REF bstrConnectionString,
REF uConnectionIp
);
if (NLBFAILED(nerr))
{
TRACE_CRIT(L"%!FUNC! gEngine.GetHostConnectionInformation fails!");
//
// We'll plow on...
//
ehConnectionIF = NULL;
uConnectionIp = 0;
}
if (ehConnectionIF == *m_pehSelectedInterfaceId)
{
//
// The selected interface is also the interface that we
// are connecting over...
//
if (iSpec.m_NlbCfg.fDHCP)
{
//
// Ouch -- it's also DHCP. We can't allow this...
//
msgLog.Log(IDS_CANT_USE_DHCP_NIC_MSG);
bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
fRet = FALSE;
goto end;
}
}
}
//
// Check if nlb is bound and if so, if it's cluster ip address
// is different.
//
if (iSpec.m_NlbCfg.IsValidNlbConfig())
{
//
// Hmm... interface is already bound to NLB.
// Let's see if the cluster IP address is different...
//
LPCWSTR szClusterIp = m_pNlbCfg->NlbParams.cl_ip_addr;
LPCWSTR szIfClusterIp = iSpec.m_NlbCfg.NlbParams.cl_ip_addr;
if ( szIfClusterIp[0]!=0
&& (_wcsspnp(szIfClusterIp, L".0")!=NULL))
{
// non-blank cluster Ip address
if (wcscmp(szClusterIp, szIfClusterIp))
{
//
// IPs don't match! Put up message box..
//
msgLog.Log(
IDS_CONNECT_MSG_IF_ALREADY_BOUND,
szFriendlyName,
iSpec.m_NlbCfg.NlbParams.domain_name,
szIfClusterIp
);
bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_CAP_IF_ALREADY_BOUND);
// szCaption = L"Interface already configured for NLB";
fOkCancel=TRUE;
fRet = FALSE;
goto end;
}
}
}
}
}
fRet = TRUE;
}
else
{
_bstr_t bstrClusterDescription;
_bstr_t bstrIpAddress;
_bstr_t bstrDomainName;
LPCWSTR szClusterDescription = NULL;
nerr = gEngine.GetClusterIdentification(
ehCluster,
REF bstrIpAddress,
REF bstrDomainName,
REF bstrDisplayName
);
if (FAILED(nerr))
{
TRACE_CRIT(L"%!FUNC!: Error 0x%lx getting ehCluster 0x%lx identification\n",
nerr, ehCluster);
bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
// szCaption = L"Unable to proceed";
msgLog.Log(IDS_CONNECT_UNABLE_TO_PROCEEED_INTERNAL);
// szMessage = L"Unable to proceed due to an internal error.";
goto end;
}
szClusterDescription = bstrDisplayName;
if (szClusterDescription==NULL)
{
szClusterDescription = L"";
}
//
// We won't allow proceeding in this case, because this indicates that
// this interface is already part of a cluster managed by NLB Manger.
//
msgLog.Log(
IDS_CONNECT_MSG_INTERFACE_ALREADY_MANAGED,
szFriendlyName,
szClusterDescription
);
bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
}
end:
if (!fRet)
{
LPCWSTR szCaption = (LPCWSTR) bstrCaption;
LPCWSTR szMessage = msgLog.GetStringSafe();
if (fOkCancel)
{
int i = MessageBox( szMessage, szCaption, MB_OKCANCEL);
if (i == IDOK)
{
fRet = TRUE;
}
}
else
{
MessageBox( szMessage, szCaption, MB_ICONSTOP | MB_OK);
}
}
return fRet;
}
BOOL g_Silent = FALSE;