/*++ Copyright(c) 1998,99 Microsoft Corporation Module Name: ports.cpp Abstract: Windows Load Balancing Service (WLBS) Notifier object UI - port rules config tab Author: kyrilf shouse --*/ #include "pch.h" #pragma hdrstop #include "ncatlui.h" #include "resource.h" #include "wlbsparm.h" #include "wlbscfg.h" #include "ports.h" #include "utils.h" #include #include "ports.tmh" #if DBG static void TraceMsg(PCWSTR pszFormat, ...); #else #define TraceMsg NOP_FUNCTION #endif #define DIALOG_LIST_STRING_SIZE 80 /* * Method: CDialogPorts * Description: The class constructor. */ CDialogPorts::CDialogPorts (NETCFG_WLBS_CONFIG * paramp, const DWORD * adwHelpIDs) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::CDialogPorts\n"); m_paramp = paramp; m_adwHelpIDs = adwHelpIDs; m_rulesValid = FALSE; m_sort_column = WLBS_VIP_COLUMN; m_sort_order = WLBS_SORT_ASCENDING; TRACE_VERB("<-%!FUNC!"); } /* * Method: ~CDialogPorts * Description: The class destructor. */ CDialogPorts::~CDialogPorts () { TRACE_VERB("<->%!FUNC!"); TraceMsg(L"CDialogPorts::~CDialogPorts\n"); } /* * Method: OnInitDialog * Description: Called to initialize the port rule properties dialog. */ LRESULT CDialogPorts::OnInitDialog (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnInitDialog\n"); LV_COLUMN lvCol; RECT rect; /* Always tell NetCfg that the page has changed, so we don't have to keep track of this. */ SetChangedFlag(); /* We are specifying the column format, text, and width. */ lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT; ::GetClientRect(GetDlgItem(IDC_LIST_PORT_RULE), &rect); int colWidth = (rect.right - 90)/(WLBS_NUM_COLUMNS - 2); /* Add all column headers to the port rule list box. */ for (int index = 0; index < WLBS_NUM_COLUMNS; index++) { /* Set column configuration based on which column we're inserting. */ switch (index) { case WLBS_VIP_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_VIP); lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 100; break; case WLBS_PORT_START_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_START); lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 43; break; case WLBS_PORT_END_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_END); lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 43; break; case WLBS_PROTOCOL_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_PROT); lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 51; break; case WLBS_MODE_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_MODE); lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 53; break; case WLBS_PRIORITY_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_PRI); lvCol.fmt = LVCFMT_CENTER; lvCol.cx = 45; break; case WLBS_LOAD_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_LOAD); lvCol.fmt = LVCFMT_CENTER; lvCol.cx = 39; break; case WLBS_AFFINITY_COLUMN: lvCol.pszText = (LPWSTR)SzLoadIds(IDS_LIST_AFF); lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 47; break; } /* Insert the column into the listbox. */ if (ListView_InsertColumn(GetDlgItem(IDC_LIST_PORT_RULE), index, &lvCol) != index) { TraceMsg(L"CDialogPorts::OnInitDialog Invalid item (%d) inserted into list view\n", index); TRACE_CRIT("%!FUNC! Invalid item (%d) inserted into list view", index); TRACE_VERB("<-%!FUNC!"); return 0; } } /* Set the extended sytles: Full row selection (as opposed to the default of column one only) */ ListView_SetExtendedListViewStyleEx(GetDlgItem(IDC_LIST_PORT_RULE), LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnContextMenu * Description: */ LRESULT CDialogPorts::OnContextMenu (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnContextMenu\n"); /* Spawn a help window. */ if (m_adwHelpIDs != NULL) ::WinHelp(m_hWnd, CVY_CTXT_HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR)m_adwHelpIDs); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnHelp * Description: */ LRESULT CDialogPorts::OnHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnHelp\n"); LPHELPINFO lphi = reinterpret_cast(lParam); /* Spawn a help window. */ if ((HELPINFO_WINDOW == lphi->iContextType) && (m_adwHelpIDs != NULL)) ::WinHelp(static_cast(lphi->hItemHandle), CVY_CTXT_HELP_FILE, HELP_WM_HELP, (ULONG_PTR)m_adwHelpIDs); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnActive * Description: Called when the port rules tab becomes active (is clicked). */ LRESULT CDialogPorts::OnActive (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnActive\n"); /* Populate the UI with the current configuration. */ SetInfo(); /* If any port rules have been defined, "snap" the listbox to the first rule. If no rules currently exist, disable the MODIFY and DELETE buttons. */ if (m_paramp->dwNumRules) { /* Select the first item in the port rule list. */ ListView_SetItemState(GetDlgItem(IDC_LIST_PORT_RULE), 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); } else { /* Since there are no port rules defined, disable the Modify and Delete buttons. */ ::EnableWindow(GetDlgItem(IDC_BUTTON_MODIFY), FALSE); ::EnableWindow(GetDlgItem(IDC_BUTTON_DEL), FALSE); } /* If the maximum number of port rules has already been defined, then disable the ADD button. */ if (m_paramp->dwNumRules >= m_paramp->dwMaxRules) ::EnableWindow(GetDlgItem(IDC_BUTTON_ADD), FALSE); ::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, 0); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnKillActive * Description: Called When the focus moves away from the port rules tab. */ LRESULT CDialogPorts::OnKillActive (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnKillActive\n"); /* Get the new configuration from the UI. */ UpdateInfo(); ::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnApply * Description: Called when the user clicks "OK". */ LRESULT CDialogPorts::OnApply (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("<->%!FUNC!"); TraceMsg(L"CDialogPorts::OnApply\n"); return 0; } /* * Method: OnCancel * Description: Called when the user clicks "Cancel". */ LRESULT CDialogPorts::OnCancel (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("<->%!FUNC!"); TraceMsg(L"CDialogPorts::OnCancel\n"); return 0; } /* * Method: OnColumnClick * Description: Called when the user clicks a column header in the listbox. */ LRESULT CDialogPorts::OnColumnClick (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnColumnClick\n"); LPNMLISTVIEW lv; switch (idCtrl) { case IDC_LIST_PORT_RULE: /* Extract the column information. */ lv = (LPNMLISTVIEW)pnmh; /* If we are sorting by the same column we were previously sorting by, then we reverse the sort order. */ if (m_sort_column == lv->iSubItem) { if (m_sort_order == WLBS_SORT_ASCENDING) m_sort_order = WLBS_SORT_DESCENDING; else if (m_sort_order == WLBS_SORT_DESCENDING) m_sort_order = WLBS_SORT_ASCENDING; } /* We sort by the column that was clicked. */ m_sort_column = lv->iSubItem; /* Teardown the listbox and make sure our data matches the state of the UI. */ UpdateInfo(); /* Rebuild the listbox, with the new sort criteria. */ SetInfo(); /* Select the first item in the port rule list. */ if (m_paramp->dwNumRules) ListView_SetItemState(GetDlgItem(IDC_LIST_PORT_RULE), 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnDoubleClick * Description: Called when the user double clicks an item in the listbox. */ LRESULT CDialogPorts::OnDoubleClick (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnDoubleClick\n"); switch (idCtrl) { case IDC_LIST_PORT_RULE: /* When an item is double-clicked, consider it an edit request. */ OnButtonModify(BN_CLICKED, 0, 0, fHandled); break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnStateChange * Description: Called when the user selects a port rule from the list. */ LRESULT CDialogPorts::OnStateChange (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnStateChange\n"); switch (idCtrl) { case IDC_LIST_PORT_RULE: LPNMLISTVIEW lv = (LPNMLISTVIEW)pnmh; int index; /* When the user selects a port rule, change the port rule description. */ if (lv->uChanged & LVIF_STATE) FillPortRuleDescription(); /* Find the index of the currently selected port rule. */ if ((index = ListView_GetNextItem(GetDlgItem(IDC_LIST_PORT_RULE), -1, LVNI_SELECTED)) == -1) { /* If no port rule is selected, then disable the edit and delete buttons. */ ::EnableWindow(GetDlgItem(IDC_BUTTON_MODIFY), FALSE); ::EnableWindow(GetDlgItem(IDC_BUTTON_DEL), FALSE); } else { /* If one is selected, make sure the edit and delete buttons are enabled. */ ::EnableWindow(GetDlgItem(IDC_BUTTON_MODIFY), TRUE); ::EnableWindow(GetDlgItem(IDC_BUTTON_DEL), TRUE); /* Give it the focus. */ ListView_SetItemState(GetDlgItem(IDC_LIST_PORT_RULE), index, LVIS_FOCUSED, LVIS_FOCUSED); } break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnDoubleClick * Description: Called when the user double clicks an item in the listbox. */ void CDialogPorts::FillPortRuleDescription () { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::FillPortRuleDescription\n"); VALID_PORT_RULE * rp = NULL; WCHAR description[512]; LV_ITEM lvItem; int index; /* Find the index of the currently selected port rule. */ if ((index = ListView_GetNextItem(GetDlgItem(IDC_LIST_PORT_RULE), -1, LVNI_SELECTED)) == -1) { /* If there is no port rule selected, then display information about how traffic not covered by the port rule set is handled. */ ::SetDlgItemText(m_hWnd, IDC_TEXT_PORT_RULE_DESCR, SzLoadIds(IDS_PORT_RULE_DEFAULT)); TRACE_INFO("%!FUNC! a port rule was no selected"); TRACE_VERB("<-%!FUNC!"); return; } /* Fill in the information for this port rule. */ lvItem.iItem = index; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; /* Get the information about this port rule. */ if (!ListView_GetItem(GetDlgItem(IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPorts::FillPortRuleDescription Unable to retrieve item %d from listbox\n", index); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox", index); TRACE_VERB("<-%!FUNC!"); return; } /* Get the data pointer for this port rule. */ if (!(rp = (VALID_PORT_RULE*)lvItem.lParam)) { TraceMsg(L"CDialogPorts::FillPortRuleDescription rule for item %d is bogus\n", index); TRACE_CRIT("%!FUNC! rule for item %d is bogus", index); TRACE_VERB("<-%!FUNC!"); return; } /* This code is terrible - for localization reasons, we require an essentially static string table entry for each possible port rule configuration. So, we have to if/switch ourselves to death trying to match this port rule with the correct string in the table - then we pop in stuff like port ranges. */ switch (rp->protocol) { case CVY_TCP: if (rp->start_port == rp->end_port) { switch (rp->mode) { case CVY_NEVER: wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORT_DISABLED), rp->start_port); break; case CVY_SINGLE: wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORT_SINGLE), rp->start_port); break; case CVY_MULTI: if (rp->mode_data.multi.equal_load) wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORT_MULTIPLE_EQUAL), rp->start_port); else wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORT_MULTIPLE_UNEQUAL), rp->start_port); switch (rp->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_NONE)); break; case CVY_AFFINITY_SINGLE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_SINGLE)); break; case CVY_AFFINITY_CLASSC: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_CLASSC)); break; } break; } } else { switch (rp->mode) { case CVY_NEVER: wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORTS_DISABLED), rp->start_port, rp->end_port); break; case CVY_SINGLE: wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORTS_SINGLE), rp->start_port, rp->end_port); break; case CVY_MULTI: if (rp->mode_data.multi.equal_load) wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORTS_MULTIPLE_EQUAL), rp->start_port, rp->end_port); else wsprintf(description, SzLoadIds(IDS_PORT_RULE_TCP_PORTS_MULTIPLE_UNEQUAL), rp->start_port, rp->end_port); switch (rp->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_NONE)); break; case CVY_AFFINITY_SINGLE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_SINGLE)); break; case CVY_AFFINITY_CLASSC: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_CLASSC)); break; } break; } } break; case CVY_UDP: if (rp->start_port == rp->end_port) { switch (rp->mode) { case CVY_NEVER: wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORT_DISABLED), rp->start_port); break; case CVY_SINGLE: wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORT_SINGLE), rp->start_port); break; case CVY_MULTI: if (rp->mode_data.multi.equal_load) wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORT_MULTIPLE_EQUAL), rp->start_port); else wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORT_MULTIPLE_UNEQUAL), rp->start_port); switch (rp->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_NONE)); break; case CVY_AFFINITY_SINGLE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_SINGLE)); break; case CVY_AFFINITY_CLASSC: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_CLASSC)); break; } break; } } else { switch (rp->mode) { case CVY_NEVER: wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORTS_DISABLED), rp->start_port, rp->end_port); break; case CVY_SINGLE: wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORTS_SINGLE), rp->start_port, rp->end_port); break; case CVY_MULTI: if (rp->mode_data.multi.equal_load) wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORTS_MULTIPLE_EQUAL), rp->start_port, rp->end_port); else wsprintf(description, SzLoadIds(IDS_PORT_RULE_UDP_PORTS_MULTIPLE_UNEQUAL), rp->start_port, rp->end_port); switch (rp->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_NONE)); break; case CVY_AFFINITY_SINGLE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_SINGLE)); break; case CVY_AFFINITY_CLASSC: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_CLASSC)); break; } break; } } break; case CVY_TCP_UDP: if (rp->start_port == rp->end_port) { switch (rp->mode) { case CVY_NEVER: wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORT_DISABLED), rp->start_port); break; case CVY_SINGLE: wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORT_SINGLE), rp->start_port); break; case CVY_MULTI: if (rp->mode_data.multi.equal_load) wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORT_MULTIPLE_EQUAL), rp->start_port); else wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORT_MULTIPLE_UNEQUAL), rp->start_port); switch (rp->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_NONE)); break; case CVY_AFFINITY_SINGLE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_SINGLE)); break; case CVY_AFFINITY_CLASSC: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_CLASSC)); break; } break; } } else { switch (rp->mode) { case CVY_NEVER: wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORTS_DISABLED), rp->start_port, rp->end_port); break; case CVY_SINGLE: wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORTS_SINGLE), rp->start_port, rp->end_port); break; case CVY_MULTI: if (rp->mode_data.multi.equal_load) wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORTS_MULTIPLE_EQUAL), rp->start_port, rp->end_port); else wsprintf(description, SzLoadIds(IDS_PORT_RULE_BOTH_PORTS_MULTIPLE_UNEQUAL), rp->start_port, rp->end_port); switch (rp->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_NONE)); break; case CVY_AFFINITY_SINGLE: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_SINGLE)); break; case CVY_AFFINITY_CLASSC: lstrcat(description, SzLoadIds(IDS_PORT_RULE_AFFINITY_CLASSC)); break; } break; } } break; } /* Set the port rule description text. */ ::SetDlgItemText(m_hWnd, IDC_TEXT_PORT_RULE_DESCR, description); TRACE_VERB("<-%!FUNC!"); } /* * Method: OnButtonAdd * Description: Called when the user clicks the ADD button. */ LRESULT CDialogPorts::OnButtonAdd (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnButtonAdd\n"); switch (wNotifyCode) { case BN_CLICKED: CDialogPortRule * portRuleDialog = NULL; /* Create a port rule properties dialog box. The invalid index tells the dialog that this operation is an ADD, so it populates the dialog box with default values. */ if (!(portRuleDialog = new CDialogPortRule(this, m_adwHelpIDs, WLBS_INVALID_PORT_RULE_INDEX))) { TraceMsg(L"CDialogPorts::OnButtonAdd Unable to allocate for ADD dialog\n"); TRACE_CRIT("%!FUNC! memory allocation failed when creating a port rule properties dialog box"); TRACE_VERB("<-%!FUNC!"); return ERROR_NOT_ENOUGH_MEMORY; } /* Show the listbox. If the user presses "OK", update the port rule list, otherwise ignore it. */ if (portRuleDialog->DoModal() == IDOK) UpdateList(TRUE, FALSE, FALSE, &portRuleDialog->m_rule); /* Free the dialog box memory. */ delete portRuleDialog; break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnButtonAdd * Description: Called when the user clicks the DELETE button. */ LRESULT CDialogPorts::OnButtonDel (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnButtonDel\n"); switch (wNotifyCode) { case BN_CLICKED: /* Call UpdateList to DELETE a port rule. */ UpdateList(FALSE, TRUE, FALSE, NULL); break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnButtonAdd * Description: Called when the user clicks the EDIT button. */ LRESULT CDialogPorts::OnButtonModify (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::OnButtonModify\n"); switch (wNotifyCode) { case BN_CLICKED: CDialogPortRule * portRuleDialog = NULL; int index; /* Find the index of the currently selected port rule. */ if ((index = ListView_GetNextItem(GetDlgItem(IDC_LIST_PORT_RULE), -1, LVNI_SELECTED)) == -1) return 0; /* Create a port rule properties dialog box. The index tells the dialog box which port rule is being modified, so the dialog can be populated with the configuration of that rule. */ if (!(portRuleDialog = new CDialogPortRule(this, m_adwHelpIDs, index))) { TraceMsg(L"CDialogPorts::OnButtonModify Unable to allocate for MODIFY dialog\n"); TRACE_CRIT("%!FUNC! memory allocation failed when creating a port rule properties dialog box"); TRACE_VERB("<-%!FUNC!"); return ERROR_NOT_ENOUGH_MEMORY; } /* Show the listbox. If the user presses "OK", update the port rule list, otherwise ignore it. */ if (portRuleDialog->DoModal() == IDOK) UpdateList(FALSE, FALSE, TRUE, &portRuleDialog->m_rule); /* Free the dialog box memory. */ delete portRuleDialog; break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: UpdateList * Description: Called when the user presses either ADD, MODIFY, or DELETE. This function * performs the appropriate function and error checking. */ void CDialogPorts::UpdateList (BOOL add, BOOL del, BOOL modify, VALID_PORT_RULE * rulep) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::UpdateList\n"); VALID_PORT_RULE * rp; LV_ITEM lvItem; int i; /* Find a slot for this rule in the array of port rules. */ if (modify) { /* For a MODIFY, we put the rule in place of the one the user modified. */ if ((i = ListView_GetNextItem(GetDlgItem(IDC_LIST_PORT_RULE), -1, LVNI_SELECTED)) == -1) { TRACE_CRIT("%!FUNC! failure while looking up a port rule for modify"); TRACE_VERB("<-%!FUNC!"); return; } /* Fill in the information for this port rule. */ lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; /* Get the information about this port rule. */ if (!ListView_GetItem(GetDlgItem(IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPorts::UpdateList MODIFY: Unable to retrieve item %d from listbox\n", i); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox for modify", i); TRACE_VERB("<-%!FUNC!"); return; } /* Get the data pointer for this port rule. */ if (!(rp = (VALID_PORT_RULE*)lvItem.lParam)) { TraceMsg(L"CDialogPorts::UpdateList rule for item %d is bogus\n", i); TRACE_CRIT("%!FUNC! rule for item %d is bogus in modify", i); TRACE_VERB("<-%!FUNC!"); return; } /* Delete the obsolete rule from the listbox. */ if (!ListView_DeleteItem(GetDlgItem(IDC_LIST_PORT_RULE), i)) { TraceMsg(L"CDialogPorts::UpdateList MODIFY: Unable to delete item %d from listbox\n", i); TRACE_CRIT("%!FUNC! unable to delete item %d from listbox for modify", i); TRACE_VERB("<-%!FUNC!"); return; } /* Now that the new rule has been validated, copy it into the array of port rules. */ CopyMemory((PVOID)rp, (PVOID)rulep, sizeof(VALID_PORT_RULE)); } else if (add) { /* For an ADD, we have to find an "empty" place for the rule in the array. */ for (i = 0; i < WLBS_MAX_RULES; i ++) /* Loop and break when we find the first invalid rule. */ if (!(rp = m_rules + i)->valid) break; /* Make sure that somehow we haven't allowed too many rules. */ ASSERT(i < WLBS_MAX_RULES); /* Now that the new rule has been validated, copy it into the array of port rules. */ CopyMemory((PVOID)rp, (PVOID)rulep, sizeof(VALID_PORT_RULE)); } else if (del) { /* For a DELETE, get the currently selected rule from the listbox. */ if ((i = ListView_GetNextItem(GetDlgItem(IDC_LIST_PORT_RULE), -1, LVNI_SELECTED)) == -1) { TRACE_CRIT("%!FUNC! failure while looking up a port rule for delete"); TRACE_VERB("<-%!FUNC!"); return; } /* Fill in the information for this port rule. */ lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; /* Get the information about this port rule. */ if (!ListView_GetItem(GetDlgItem(IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPorts::UpdateList DEL: Unable to retrieve item %d from listbox\n", i); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox for delete", i); TRACE_VERB("<-%!FUNC!"); return; } /* Get the data pointer for this rule and invalidate the rule. */ if (!(rp = (VALID_PORT_RULE*)lvItem.lParam)) { TraceMsg(L"CDialogPorts::UpdateList rule for item %d is bogus\n", i); TRACE_CRIT("%!FUNC! rule for item %d is bogus in delete", i); TRACE_VERB("<-%!FUNC!"); return; } rp->valid = FALSE; /* Delete the obsolete rule from the listbox. */ if (!ListView_DeleteItem(GetDlgItem(IDC_LIST_PORT_RULE), i)) { TraceMsg(L"CDialogPorts::UpdateList DEL: Unable to delete item %d from listbox\n", i); TRACE_CRIT("%!FUNC! unable to delete item %d from listbox for delete", i); TRACE_VERB("<-%!FUNC!"); return; } if (ListView_GetItemCount(GetDlgItem(IDC_LIST_PORT_RULE)) > i) { /* This was NOT the last (in order) port rule in the list, so highlight the port rule in the same position in the list box. */ ListView_SetItemState(GetDlgItem(IDC_LIST_PORT_RULE), i, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); } else if (ListView_GetItemCount(GetDlgItem(IDC_LIST_PORT_RULE)) > 0) { /* This was the last (in order) port rule in the list, so we highlight the rule "behind" us in the list - our position minus one. */ ListView_SetItemState(GetDlgItem(IDC_LIST_PORT_RULE), i - 1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); } else { /* This was the last port rule (by count), so disable DELETE and MODIFY. */ ::EnableWindow(GetDlgItem(IDC_BUTTON_DEL), FALSE); ::EnableWindow(GetDlgItem(IDC_BUTTON_MODIFY), FALSE); } /* Each time we DELETE a rule, we can enable the enable the ADD button, because we can be certain the room now exists for a new rule. */ ::EnableWindow(GetDlgItem(IDC_BUTTON_ADD), TRUE); TRACE_INFO("%!FUNC! port rule deleted."); TRACE_VERB("<-%!FUNC!"); return; } else { TRACE_CRIT("%!FUNC! unexpect action for port rule. Not an add, modify or delete."); TRACE_VERB("<-%!FUNC!"); return; } /* Create the rule and select it in the listbox. */ CreateRule(TRUE, rp); /* Whenever we ADD a rule, check to see whether we have to disable the ADD button (when we have reached the maximum number of rules, we can no longer allow ADDs. */ if (add && (ListView_GetItemCount(GetDlgItem(IDC_LIST_PORT_RULE)) >= (int)m_paramp->dwMaxRules)) ::EnableWindow(GetDlgItem(IDC_BUTTON_ADD), FALSE); TRACE_VERB("<-%!FUNC!"); } /* * Method: InsertRule * Description: Determines where to insert a new rule into the listbox. */ int CDialogPorts::InsertRule (VALID_PORT_RULE * rulep) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::InsertRule\n"); WCHAR buf[DIALOG_LIST_STRING_SIZE]; WCHAR tmp[DIALOG_LIST_STRING_SIZE]; int index; DWORD id, NewIpAddr; /* Determine sort field contents by column. */ switch (m_sort_column) { case WLBS_VIP_COLUMN: /* Use the Vip */ NewIpAddr = htonl(IpAddressFromAbcdWsz(rulep->virtual_ip_addr)); break; case WLBS_PORT_START_COLUMN: /* Use the start port. */ swprintf(tmp, L"%5d", rulep->start_port); break; case WLBS_PORT_END_COLUMN: /* Use the end port. */ swprintf(tmp, L"%5d", rulep->end_port); break; case WLBS_PROTOCOL_COLUMN: /* Find the protocol for this port rule. */ switch (rulep->protocol) { case CVY_TCP: id = IDS_LIST_TCP; break; case CVY_UDP: id = IDS_LIST_UDP; break; case CVY_TCP_UDP: id = IDS_LIST_BOTH; break; } /* Use the protocol. */ swprintf(tmp, L"%ls", SzLoadIds(id)); break; case WLBS_MODE_COLUMN: /* Find the mode for this port rule. */ switch (rulep->mode) { case CVY_SINGLE: id = IDS_LIST_SINGLE; break; case CVY_MULTI: id = IDS_LIST_MULTIPLE; break; case CVY_NEVER: id = IDS_LIST_DISABLED; break; } /* Use the mode. */ swprintf(tmp, L"%ls", SzLoadIds(id)); break; case WLBS_PRIORITY_COLUMN: /* In single host filtering, we use the priority. If this rule does not use single host filtering, and therefore does not have a filtering priority, we insert at the end. */ if (rulep->mode == CVY_SINGLE) swprintf(tmp, L"%2d", rulep->mode_data.single.priority); else { TRACE_VERB("<-%!FUNC!"); return (int)m_paramp->dwMaxRules; } break; case WLBS_LOAD_COLUMN: /* In multiple host filtering, use the load, which can be "Equal" or an integer. If this rule does not use multiple host filtering, and therefore does not have a load weight, we insert at the end. */ if (rulep->mode == CVY_MULTI) { if (rulep->mode_data.multi.equal_load) swprintf(tmp, L"%ls", SzLoadIds(IDS_LIST_EQUAL)); else swprintf(tmp, L"%3d", rulep->mode_data.multi.load); } else { TRACE_VERB("<-%!FUNC!"); return (int)m_paramp->dwMaxRules; } break; case WLBS_AFFINITY_COLUMN: /* Find the affinity for this port rule. Rules that do not use multiple host filtering will not have an affinity setting - that's fine. Ignore this here. */ switch (rulep->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: id = IDS_LIST_ANONE; break; case CVY_AFFINITY_SINGLE: id = IDS_LIST_ASINGLE; break; case CVY_AFFINITY_CLASSC: id = IDS_LIST_ACLASSC; break; } /* In multiple host filtering, use the affinity. If this port rule does not use multiple host filtering, and therefore does not have an affinity, we insert at the end. */ if (rulep->mode == CVY_MULTI) swprintf(tmp, L"%ls", SzLoadIds(id)); else { TRACE_VERB("<-%!FUNC!"); return (int)m_paramp->dwMaxRules; } break; } /* Loop through the listbox to find the place to insert the new rule, in port range order. */ for (index = 0; index < ::SendDlgItemMessage(m_hWnd, IDC_LIST_PORT_RULE, LVM_GETITEMCOUNT, 0, 0); index ++) { LV_ITEM lvItem; DWORD CurIpAddr; /* Fill in the information to retrieve the corresponding list entry for the column by which we are sorting. */ lvItem.iItem = index; lvItem.iSubItem = m_sort_column; lvItem.mask = LVIF_TEXT; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = buf; lvItem.cchTextMax = DIALOG_LIST_STRING_SIZE; /* Get the item from the listbox. */ if (!ListView_GetItem(GetDlgItem(IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPorts::InsertRule Unable to retrieve item %d from listbox\n", index); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox", index); TRACE_VERB("<-%!FUNC!"); return (int)m_paramp->dwMaxRules; } // If the coolumn to sort on is VIP, get the vip in the list box if (m_sort_column == WLBS_VIP_COLUMN) { if (!wcscmp(lvItem.pszText, SzLoadIds(IDS_LIST_ALL_VIP))) CurIpAddr = htonl(IpAddressFromAbcdWsz(CVY_DEF_ALL_VIP)); else CurIpAddr = htonl(IpAddressFromAbcdWsz(lvItem.pszText)); } if (m_sort_order == WLBS_SORT_ASCENDING) { /* If the column subitem is empty, then we insert in front of it. */ if (!wcscmp(lvItem.pszText, L"")) break; /* Compare IP Addresses as DWORDS for VIPs */ /* If this rule is "greater" than the new rule, then this is where we insert. */ if (m_sort_column == WLBS_VIP_COLUMN) { if (CurIpAddr >= NewIpAddr) break; } else // Other columns { if (wcscmp(lvItem.pszText, tmp) >= 0) break; } } else if (m_sort_order == WLBS_SORT_DESCENDING) { /* Compare IP Addresses as DWORDS for VIPs */ /* If this rule is "less" than the new rule, then this is where we insert. */ if (m_sort_column == WLBS_VIP_COLUMN) { if (CurIpAddr <= NewIpAddr) break; } else // Other columns { if (wcscmp(lvItem.pszText, tmp) <= 0) break; } } } TRACE_VERB("<-%!FUNC!"); return index; } /* * Method: CreateRule * Description: Adds a rule to the port rule list box. */ void CDialogPorts::CreateRule (BOOL select, VALID_PORT_RULE * rulep) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::CreateRule\n"); WCHAR buf[DIALOG_LIST_STRING_SIZE]; WCHAR tmp[DIALOG_LIST_STRING_SIZE]; LV_ITEM lvItem; DWORD id; int index; /* Find out at what index we are inserting into the listbox. */ index = InsertRule(rulep); /* Insert the vip column, If Vip is "All Vip", insert the corresponding string, else insert the IP address */ if (!lstrcmpi(rulep->virtual_ip_addr, CVY_DEF_ALL_VIP)) { swprintf(buf, L"%ls", SzLoadIds(IDS_LIST_ALL_VIP)); } else { swprintf(buf, L"%ls", rulep->virtual_ip_addr); } /* Fill in the information to insert this item into the list and set the lParam to the pointer for this port rule. This makes it trivial to retrieve the port rule structure from the listbox later. */ lvItem.iItem = index; lvItem.iSubItem = 0; lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; lvItem.pszText = buf; lvItem.lParam = (LPARAM)rulep; /* Insert this item into the list. */ if ((index = ListView_InsertItem(GetDlgItem(IDC_LIST_PORT_RULE), &lvItem)) == -1) { TraceMsg(L"CDialogPorts::CreateRule Unable to insert item into listbox\n"); TRACE_CRIT("%!FUNC! unable to insert item into listbox"); TRACE_VERB("<-%!FUNC!"); return; } swprintf(buf, L"%5d", rulep->start_port); /* Set the text associated with the start port subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_PORT_START_COLUMN, buf); swprintf(buf, L"%5d", rulep->end_port); /* Set the text associated with the end port subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_PORT_END_COLUMN, buf); /* Find the string table entry corresponding to the selected protocol. */ switch (rulep->protocol) { case CVY_TCP: id = IDS_LIST_TCP; break; case CVY_UDP: id = IDS_LIST_UDP; break; case CVY_TCP_UDP: id = IDS_LIST_BOTH; break; } swprintf(buf, L"%ls", SzLoadIds(id)); /* Set the text associated with the protocol subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_PROTOCOL_COLUMN, buf); switch (rulep->mode) { case CVY_SINGLE: /* Single host filetering fills in only the mode and priority fields. */ swprintf(buf, L"%ls", SzLoadIds(IDS_LIST_SINGLE)); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_MODE_COLUMN, buf); swprintf(buf, L"%2d", rulep->mode_data.single.priority); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_PRIORITY_COLUMN, buf); break; case CVY_MULTI: /* Find the appropriate string table entry for the affinity. */ switch (rulep->mode_data.multi.affinity) { case CVY_AFFINITY_NONE: id = IDS_LIST_ANONE; break; case CVY_AFFINITY_SINGLE: id = IDS_LIST_ASINGLE; break; case CVY_AFFINITY_CLASSC: id = IDS_LIST_ACLASSC; break; } /* Multiple host filtering fills in the mode, load, and affinity fields. */ swprintf(buf, L"%ls", SzLoadIds(IDS_LIST_MULTIPLE)); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_MODE_COLUMN, buf); if (rulep->mode_data.multi.equal_load) { swprintf(buf, L"%ls", SzLoadIds(IDS_LIST_EQUAL)); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_LOAD_COLUMN, buf); } else { swprintf(buf, L"%3d", rulep->mode_data.multi.load); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_LOAD_COLUMN, buf); } swprintf(buf, L"%ls", SzLoadIds(id)); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_AFFINITY_COLUMN, buf); break; case CVY_NEVER: /* Disabled filtering only fills in the mode field. */ swprintf(buf, L"%ls", SzLoadIds(IDS_LIST_DISABLED)); /* Set the text associated with this subitem. */ ListView_SetItemText(GetDlgItem(IDC_LIST_PORT_RULE), index, WLBS_MODE_COLUMN, buf); break; } if (select) { /* Select the first item in the port rule list. */ ListView_SetItemState(GetDlgItem(IDC_LIST_PORT_RULE), index, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); /* If we select a port rule in the list, we should enable the MODIFY and REMOVE buttons. */ ::EnableWindow(GetDlgItem(IDC_BUTTON_DEL), TRUE); ::EnableWindow(GetDlgItem(IDC_BUTTON_MODIFY), TRUE); } TRACE_VERB("<-%!FUNC!"); } /* * Method: SetInfo * Description: Called to populate the UI with the port rule settings. */ void CDialogPorts::SetInfo() { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::SetInfo\n"); VALID_PORT_RULE * rp; DWORD i; /* Empty the port rule memory. */ memset(m_rules, 0, sizeof(m_rules)); /* Get rid of all rules in the list box. */ if (!ListView_DeleteAllItems(GetDlgItem(IDC_LIST_PORT_RULE))) { TraceMsg(L"CDialogPorts::SetInfo Unable to delete all items from listbox\n"); TRACE_CRIT("%!FUNC! unable to delete all items from listbox"); TRACE_VERB("<-%!FUNC!"); return; } /* Re-insert all port rules. */ for (i = 0; i < m_paramp->dwNumRules; i ++) { *(NETCFG_WLBS_PORT_RULE *)&m_rules[i] = m_paramp->port_rules[i]; /* Validate the port rule. */ rp = m_rules + i; rp->valid = TRUE; /* Call CreateRule to insert the rule into the list. */ CreateRule(FALSE, m_rules + i); } /* Mark the listbox rules as valid. */ m_rulesValid = TRUE; TRACE_VERB("<-%!FUNC!"); } /* * Method: UpdateInfo * Description: Called to copy the UI state to the port rule configuration. */ void CDialogPorts::UpdateInfo() { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPorts::UpdateInfo\n"); VALID_PORT_RULE * rulep; DWORD i; /* If the rules are invalid, i.e. the listbox does not currently reflect the actual state of the port rules, then bail out. */ if (!m_rulesValid) { TRACE_INFO("%!FUNC! rules are invalid and can't be processed"); TRACE_VERB("<-%!FUNC!"); return; } /* Empty the port rule memory. */ memset(m_paramp->port_rules, 0, sizeof(m_paramp->port_rules)); /* Set the number of port rules to the number of entries in the listbox. */ m_paramp->dwNumRules = ListView_GetItemCount(GetDlgItem(IDC_LIST_PORT_RULE)); /* For each rule, retrieve the data pointer and store it. */ for (i = 0; i < m_paramp->dwNumRules; i++) { LV_ITEM lvItem; /* Fill in the information necessary to retrive the port rule data pointer. */ lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; /* Get the listbox item information. */ if (!ListView_GetItem(GetDlgItem(IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPorts::UpdateInfo Unable to retrieve item %d from listbox\n", i); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox", i); TRACE_VERB("<-%!FUNC!"); return; } /* Get the data pointer for this port rule. */ if (!(rulep = (VALID_PORT_RULE*)lvItem.lParam)) { TraceMsg(L"CDialogPorts::UpdateInfo rule for item %d is bogus\n", i); TRACE_CRIT("%!FUNC! rule for item %d is bogus", i); TRACE_VERB("<-%!FUNC!"); return; } /* Make sure the port rule is valid. This should never happen because invalid rules are not added to the list!!!. */ if (!rulep->valid) { TraceMsg(L"CDialogPorts::UpdateInfo Rule %d invalid\n", i); TRACE_CRIT("%!FUNC! invalid rule %d will be skipped", i); continue; } /* Store the valid port rule. */ m_paramp->port_rules[i] = *(NETCFG_WLBS_PORT_RULE *)rulep; } /* Mark the listbox rules as invalid. */ m_rulesValid = FALSE; TRACE_VERB("<-%!FUNC!"); } #if DBG /* * Function: TraceMsg * Description: Generate a trace or error message. */ void TraceMsg(PCWSTR pszFormat, ...) { static WCHAR szTempBufW[4096]; static CHAR szTempBufA[4096]; va_list arglist; va_start(arglist, pszFormat); vswprintf(szTempBufW, pszFormat, arglist); /* Convert the WCHAR to CHAR. This is for backward compatability with TraceMsg so that it was not necessary to change all pre-existing calls thereof. */ WideCharToMultiByte(CP_ACP, 0, szTempBufW, -1, szTempBufA, 4096, NULL, NULL); /* Traced messages are now sent through the netcfg TraceTag routine so that they can be turned on/off dynamically. */ TraceTag(ttidWlbs, szTempBufA); va_end(arglist); } #endif /* * Method: CDialogPortRule * Description: The class constructor. */ CDialogPortRule::CDialogPortRule (CDialogPorts * parent, const DWORD * adwHelpIDs, int index) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::CDialogPortRule\n"); m_adwHelpIDs = adwHelpIDs; m_index = index; m_parent = parent; ZeroMemory(&m_IPFieldChangeState, sizeof(m_IPFieldChangeState)); TRACE_VERB("<-%!FUNC!"); } /* * Method: ~CDialogPortRule * Description: The class destructor. */ CDialogPortRule::~CDialogPortRule () { TRACE_VERB("<->%!FUNC!"); TraceMsg(L"CDialogPortRule::~CDialogPortRule\n"); } /* * Method: OnInitDialog * Description: Called to initialize the port rule properties dialog. */ LRESULT CDialogPortRule::OnInitDialog (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnInitDialog\n"); RECT rect; /* Position this window with the upper-left corner matching the upper left corner of the port rule list box in the parent window. Simply for consistency. */ ::GetWindowRect(::GetDlgItem(m_parent->m_hWnd, IDC_LIST_PORT_RULE), &rect); SetWindowPos(NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); /* Limit the field ranges for the port rule properties. */ ::SendDlgItemMessage(m_hWnd, IDC_EDIT_START, EM_SETLIMITTEXT, 5, 0); ::SendDlgItemMessage(m_hWnd, IDC_EDIT_END, EM_SETLIMITTEXT, 5, 0); ::SendDlgItemMessage(m_hWnd, IDC_EDIT_MULTI, EM_SETLIMITTEXT, 3, 0); ::SendDlgItemMessage(m_hWnd, IDC_EDIT_SINGLE, EM_SETLIMITTEXT, 2, 0); ::SendDlgItemMessage(m_hWnd, IDC_SPIN_SINGLE, UDM_SETRANGE32, CVY_MIN_MAX_HOSTS, CVY_MAX_MAX_HOSTS); ::SendDlgItemMessage(m_hWnd, IDC_SPIN_MULTI, UDM_SETRANGE32, CVY_MIN_LOAD, CVY_MAX_LOAD); ::SendDlgItemMessage(m_hWnd, IDC_SPIN_START, UDM_SETRANGE32, CVY_MIN_PORT, CVY_MAX_PORT); ::SendDlgItemMessage(m_hWnd, IDC_SPIN_END, UDM_SETRANGE32, CVY_MIN_PORT, CVY_MAX_PORT); /* Limit the zeroth field of the cluster IP address between 1 and 223. */ ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PORT_RULE_VIP, IPM_SETRANGE, 0, (LPARAM)MAKEIPRANGE(WLBS_IP_FIELD_ZERO_LOW, WLBS_IP_FIELD_ZERO_HIGH)); /* Invalidate the rule. The validity will be checked upon clicking "OK". */ m_rule.valid = FALSE; /* Populate the UI with the current configuration. */ SetInfo(); /* Set the cursor to be the arrow. For some reason, if we don't do this, then the cursor will remain an hourglass until the mouse moves over any UI element. Probably need to call CPropertPage constructor to fix this? */ SetCursor(LoadCursor(NULL, IDC_ARROW)); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnContextMenu * Description: */ LRESULT CDialogPortRule::OnContextMenu (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnContextMenu\n"); /* Spawn a help window. */ if (m_adwHelpIDs != NULL) ::WinHelp(m_hWnd, CVY_CTXT_HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR)m_adwHelpIDs); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnHelp * Description: */ LRESULT CDialogPortRule::OnHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnHelp\n"); LPHELPINFO lphi = reinterpret_cast(lParam); /* Spawn a help window. */ if ((HELPINFO_WINDOW == lphi->iContextType) && (m_adwHelpIDs != NULL)) ::WinHelp(static_cast(lphi->hItemHandle), CVY_CTXT_HELP_FILE, HELP_WM_HELP, (ULONG_PTR)m_adwHelpIDs); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnOk * Description: Called when the user clicks "OK". */ LRESULT CDialogPortRule::OnOk (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnOk\n"); BOOL fSuccess = FALSE; DWORD IPAddr; /* If "All" is Checked, then, initialize with CVY_ALL_VIP_STRING */ if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_PORT_RULE_ALL_VIP) == BST_CHECKED) { lstrcpy(m_rule.virtual_ip_addr, CVY_DEF_ALL_VIP); } else // UnChecked { /* Check for Blank Virtual IP Address */ if (::SendMessage(::GetDlgItem(m_hWnd, IDC_EDIT_PORT_RULE_VIP), IPM_ISBLANK, 0, 0)) { /* Alert the user. */ NcMsgBox(::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_VIP_BLANK, MB_APPLMODAL | MB_ICONSTOP | MB_OK); /* An error occurred. */ TRACE_CRIT("%!FUNC! No virtual IP address provided for a port rule"); TRACE_VERB("<-%!FUNC!"); return PSNRET_INVALID; } /* Get the Virtual IP address as a string and DWORD. */ ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PORT_RULE_VIP, WM_GETTEXT, CVY_MAX_CL_IP_ADDR, (LPARAM)m_rule.virtual_ip_addr); ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PORT_RULE_VIP, IPM_GETADDRESS, 0, (LPARAM)&IPAddr); /* Make sure that the first octet is not zero. If it is, make it 1 and alter the user. */ if (!FIRST_IPADDRESS(IPAddr)) { /* Make the first octet 1 instead of the erroneous 0. */ IPAddr = IPAddr | (DWORD)(WLBS_IP_FIELD_ZERO_LOW << 24); /* Set the IP address and update our cluster IP address string. */ ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PORT_RULE_VIP, IPM_SETADDRESS, 0, (LPARAM)IPAddr); //::SendDlgItemMessage(m_hWnd, IDC_EDIT_PORT_RULE_VIP, WM_GETTEXT, CVY_MAX_CL_IP_ADDR, (LPARAM)m_rule.virtual_ip_addr); /* Alert the user. */ PrintIPRangeError(IDS_PARM_CL_IP_FIELD, 0, WLBS_IP_FIELD_ZERO_LOW, WLBS_IP_FIELD_ZERO_HIGH); TRACE_CRIT("%!FUNC! invalid first octect value for IP address"); TRACE_VERB("<-%!FUNC!"); return PSNRET_INVALID; } } /* Find out which protocol has been selected. */ if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_TCP)) m_rule.protocol = CVY_TCP; else if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_UDP)) m_rule.protocol = CVY_UDP; else m_rule.protocol = CVY_TCP_UDP; /* Get the start port for this rule. */ m_rule.start_port = ::GetDlgItemInt(m_hWnd, IDC_EDIT_START, &fSuccess, FALSE); /* The error code from GetDlgItemInt() indicates an error converting the alphanumeric string to an integer. This allows us to check for empty fields, assuming that because we otherwise limit the user input to digits, there will be no errors of any other type. */ if (!fSuccess) { /* Alert the user. */ PrintRangeError(IDS_PARM_PORT_BLANK, CVY_MIN_PORT, CVY_MAX_PORT); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_START)); TRACE_CRIT("%!FUNC! no start port value provided"); TRACE_VERB("<-%!FUNC!"); return 0; } /* Get the end port for this rule. */ m_rule.end_port = ::GetDlgItemInt(m_hWnd, IDC_EDIT_END, &fSuccess, FALSE); /* The error code from GetDlgItemInt() indicates an error converting the alphanumeric string to an integer. This allows us to check for empty fields, assuming that because we otherwise limit the user input to digits, there will be no errors of any other type. */ if (!fSuccess) { /* Alert the user. */ PrintRangeError(IDS_PARM_PORT_BLANK, CVY_MIN_PORT, CVY_MAX_PORT); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_END)); TRACE_CRIT("%!FUNC! no end port value provided"); TRACE_VERB("<-%!FUNC!"); return 0; } /* Make sure that the start port value falls within the valid range. */ if (/* m_rule.start_port < CVY_MIN_PORT || */ m_rule.start_port > CVY_MAX_PORT) { /* Alert the user. */ PrintRangeError(IDS_PARM_PORT_VAL, CVY_MIN_PORT, CVY_MAX_PORT); /* Force the start port to fall into the range, effectively helping the user. */ /* CVY_CHECK_MIN(m_rule.start_port, CVY_MIN_PORT); */ CVY_CHECK_MAX(m_rule.start_port, CVY_MAX_PORT); /* Set the start port to the now valid entry. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_START, m_rule.start_port, FALSE); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_START)); TRACE_CRIT("%!FUNC! invalid start port value"); TRACE_VERB("<-%!FUNC!"); return 0; } /* Make sure that the end port value falls within the valid range. */ if (/* m_rule.end_port < CVY_MIN_PORT || */ m_rule.end_port > CVY_MAX_PORT) { /* Alert the user. */ PrintRangeError(IDS_PARM_PORT_VAL, CVY_MIN_PORT, CVY_MAX_PORT); /* Force the end port to fall into the range, effectively helping the user. */ /* CVY_CHECK_MIN(m_rule.end_port, CVY_MIN_PORT); */ CVY_CHECK_MAX(m_rule.end_port, CVY_MAX_PORT); /* Set the end port to the now valid entry. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_END, m_rule.end_port, FALSE); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_END)); TRACE_CRIT("%!FUNC! invalid end port value"); TRACE_VERB("<-%!FUNC!"); return 0; } /* Retrieve the filtering mode settings. */ if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_SINGLE)) { /* The user has selected single host filtering. */ m_rule.mode = CVY_SINGLE; /* Get the handling priority. */ m_rule.mode_data.single.priority = ::GetDlgItemInt(m_hWnd, IDC_EDIT_SINGLE, &fSuccess, FALSE); /* The error code from GetDlgItemInt() indicates an error converting the alphanumeric string to an integer. This allows us to check for empty fields, assuming that because we otherwise limit the user input to digits, there will be no errors of any other type. */ if (!fSuccess) { /* Alert the user. */ PrintRangeError(IDS_PARM_HPRI_BLANK, CVY_MIN_PRIORITY, CVY_MAX_PRIORITY); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_SINGLE)); TRACE_CRIT("%!FUNC! a handling priority is required but was not provided"); TRACE_VERB("<-%!FUNC!"); return 0; } /* Make sure that the handling priority falls within the valid range. */ if (m_rule.mode_data.single.priority > CVY_MAX_PRIORITY || m_rule.mode_data.single.priority < CVY_MIN_PRIORITY) { /* Alert the user. */ PrintRangeError(IDS_PARM_SINGLE, CVY_MIN_PRIORITY, CVY_MAX_PRIORITY); /* Force the handling priority to fall into the range, effectively helping the user. */ CVY_CHECK_MIN(m_rule.mode_data.single.priority, CVY_MIN_PRIORITY); CVY_CHECK_MAX(m_rule.mode_data.single.priority, CVY_MAX_PRIORITY); /* Set the handling priority to the now valid entry. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_SINGLE, m_rule.mode_data.single.priority, FALSE); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_SINGLE)); TRACE_CRIT("%!FUNC! an invalid handling priority was provided"); TRACE_VERB("<-%!FUNC!"); return 0; } } else if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_MULTIPLE)) { /* The user has selected multiple host filtering. */ m_rule.mode = CVY_MULTI; if (::IsDlgButtonChecked (m_hWnd, IDC_CHECK_EQUAL)) { /* If the users has chosen equal load, then note this fact. */ m_rule.mode_data.multi.equal_load = TRUE; } else { /* Otherwise, they have specified a specific load weight. */ m_rule.mode_data.multi.equal_load = FALSE; /* Get the load weight. */ m_rule.mode_data.multi.load = ::GetDlgItemInt(m_hWnd, IDC_EDIT_MULTI, &fSuccess, FALSE); /* The error code from GetDlgItemInt() indicates an error converting the alphanumeric string to an integer. This allows us to check for empty fields, assuming that because we otherwise limit the user input to digits, there will be no errors of any other type. */ if (!fSuccess) { /* Alert the user. */ PrintRangeError(IDS_PARM_LOAD_BLANK, CVY_MIN_LOAD, CVY_MAX_LOAD); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_MULTI)); TRACE_CRIT("%!FUNC! a load weight is required but was not provided"); TRACE_VERB("<-%!FUNC!"); return 0; } /* Make sure that the load weight falls within the valid range. */ if (/* m_rule.mode_data.multi.load < CVY_MIN_LOAD || */ m_rule.mode_data.multi.load > CVY_MAX_LOAD) { /* Alert the user. */ PrintRangeError(IDS_PARM_LOAD, CVY_MIN_LOAD, CVY_MAX_LOAD); /* Force the load weight to fall into the range, effectively helping the user. */ /* CVY_CHECK_MIN(m_rule.mode_data.multi.load, CVY_MIN_LOAD); */ CVY_CHECK_MAX(m_rule.mode_data.multi.load, CVY_MAX_LOAD); /* Set the load weight to the now valid entry. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_MULTI, m_rule.mode_data.multi.load, FALSE); /* Return the focus to the erred entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_MULTI)); TRACE_CRIT("%!FUNC! an invalid load weight was provided"); TRACE_VERB("<-%!FUNC!"); return 0; } } /* Find out which affinity setting has been selected. */ if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_AFF_CLASSC)) m_rule.mode_data.multi.affinity = CVY_AFFINITY_CLASSC; else if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_AFF_SINGLE)) m_rule.mode_data.multi.affinity = CVY_AFFINITY_SINGLE; else m_rule.mode_data.multi.affinity = CVY_AFFINITY_NONE; } else { /* The user has selected no filtering (disabled). */ m_rule.mode = CVY_NEVER; } /* Validate the rule. If it is invalid, just bail out. */ if (!ValidateRule(&m_rule, (m_index != WLBS_INVALID_PORT_RULE_INDEX) ? FALSE : TRUE)) { TRACE_CRIT("%!FUNC! rule validation failed"); TRACE_VERB("<-%!FUNC!"); return 0; } /* If we get here, then the rule is valid. */ m_rule.valid = TRUE; /* Close the dialog and note that the user clicked "OK". */ EndDialog(IDOK); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: ValidateRule * Description: Check a port rule for validity, including enforcing the non-overlap of port ranges. */ BOOL CDialogPortRule::ValidateRule (VALID_PORT_RULE * rulep, BOOL self_check) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::ValidateRule\n"); VALID_PORT_RULE * rp; int i, index, count; /* Verify that the virtual ip address is not the same as the dip */ if (IpAddressFromAbcdWsz(rulep->virtual_ip_addr) == IpAddressFromAbcdWsz(m_parent->m_paramp->ded_ip_addr)) { /* Alert the user. */ NcMsgBox(::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_VIP_CONFLICT_DIP, MB_APPLMODAL | MB_ICONSTOP | MB_OK); /* Return focus to the invalid entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_PORT_RULE_VIP)); /* Invalidate the rule. */ rulep->valid = FALSE; TRACE_CRIT("%!FUNC! virtual IP address and dedicated IP address are the same: %ls", rulep->virtual_ip_addr); TRACE_VERB("<-%!FUNC!"); return FALSE; } /* Make sure that the end port is greater than or equal to the start port. */ if (rulep->start_port > rulep->end_port) { TRACE_CRIT("%!FUNC! start port %d is greater than end port %d", rulep->start_port, rulep->end_port); /* If the end port is less than the start port, generate an error and set the value of the erroneous end port to the value of the start port. */ rulep->end_port = rulep->start_port; /* Alert the user. */ NcMsgBox(::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_RANGE, MB_APPLMODAL | MB_ICONSTOP | MB_OK); /* Populate the UI with the new (conforming) end port value. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_END, rulep->end_port, FALSE); /* Return focus to the invalid entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_END)); /* Invalidate the rule. */ rulep->valid = FALSE; TRACE_VERB("<-%!FUNC!"); return FALSE; } /* Find out how many rules are currently in the listbox. */ count = ListView_GetItemCount(::GetDlgItem(m_parent->m_hWnd, IDC_LIST_PORT_RULE)); for (i = 0; i < count; i ++) { LV_ITEM lvItem; /* If this is a MODIFY operation, do not check against ourselves */ if (!self_check && (i == m_index)) continue; /* Fill in the information necessary to retrieve the port rule data pointer. */ lvItem.iItem = i; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; /* Get the item from the listbox. */ if (!ListView_GetItem(::GetDlgItem(m_parent->m_hWnd, IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPortRule::ValidateRule Unable to retrieve item %d from listbox\n", i); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox", i); TRACE_VERB("<-%!FUNC!"); return FALSE; } /* Get the data pointer for the i'th port rule in the list. */ if (!(rp = (VALID_PORT_RULE*)lvItem.lParam)) { TraceMsg(L"CDialogPortRule::ValidateRule rule for item %d is bogus\n", i); TRACE_CRIT("%!FUNC! rule for item %d is bogus", i); TRACE_VERB("<-%!FUNC!"); return FALSE; } /* Make sure the port rule is valid. This should never happen because invalid rules are not added to the list!!!. */ if (!rp->valid) { TraceMsg(L"CDialogPortRule::ValidateRule Rule %d invalid\n", i); TRACE_VERB("%!FUNC! rule %d invalid and will be skipped", i); continue; } /* Check for overlapping port ranges. */ if ((IpAddressFromAbcdWsz(rulep->virtual_ip_addr) == IpAddressFromAbcdWsz(rp->virtual_ip_addr)) && (((rulep->start_port < rp->start_port) && (rulep->end_port >= rp->start_port)) || ((rulep->start_port >= rp->start_port) && (rulep->start_port <= rp->end_port)))) { /* Alert the user. */ NcMsgBox(::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_OVERLAP, MB_APPLMODAL | MB_ICONSTOP | MB_OK); /* Set the listbox selection to be the conflicting rule. */ ::SendDlgItemMessage(m_hWnd, IDC_LIST_PORT_RULE, LB_SETCURSEL, i, 0); /* Return focus to the invalid entry. */ ::SetFocus(GetDlgItem(IDC_EDIT_START)); /* Invalidate the rule. */ rulep->valid = FALSE; TRACE_CRIT("%!FUNC! a port rule overlaps with the port range of another rule and will be rejected"); TRACE_VERB("<-%!FUNC!"); return FALSE; } } TRACE_VERB("<-%!FUNC!"); return TRUE; } /* * Method: OnCancel * Description: Called when the user clicks "Cancel". */ LRESULT CDialogPortRule::OnCancel (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnCancel\n"); /* Close the dialog and note that the user clicked "Cancel". */ EndDialog(IDCANCEL); TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: PrintIPRangeError * Description: Displays a message box warning the user of an out-of-range entry in * an IP address octet. */ void CDialogPortRule::PrintIPRangeError (unsigned int ids, int value, int low, int high) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::PrintIPRangeError\n"); WCHAR szCurrent[10]; WCHAR szLow[10]; WCHAR szHigh[10]; /* Fill in the allowed range and the offending value. */ wsprintfW(szHigh, L"%d", high); wsprintfW(szCurrent, L"%d", value); wsprintfW(szLow, L"%d", low); /* Pop-up a message box. */ NcMsgBox(m_hWnd, IDS_PARM_ERROR, ids, MB_APPLMODAL | MB_ICONSTOP | MB_OK, szCurrent, szLow, szHigh); TRACE_CRIT("%!FUNC! an IP address octect with value %ls is out of range", szCurrent); TRACE_VERB("<-%!FUNC!"); } /* * Method: OnIpFieldChange * Description: Called wnen a field (byte) of the cluster IP address changes. We use this * to make sure the first byte of the IP is not < 1 or > 223. */ LRESULT CDialogPortRule::OnIpFieldChange (int idCtrl, LPNMHDR pnmh, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnIpFieldChange\n"); LPNMIPADDRESS Ip; int low, high; Ip = (LPNMIPADDRESS)pnmh; switch(idCtrl) { case IDC_EDIT_PORT_RULE_VIP: /* Field zero of the cluster IP address has different limits. */ if (!Ip->iField) { low = WLBS_IP_FIELD_ZERO_LOW; high = WLBS_IP_FIELD_ZERO_HIGH; } else { low = WLBS_FIELD_LOW; high = WLBS_FIELD_HIGH; } /* The notifier may call us twice for the same change, so we have to do the bookkeeping to make sure we only alert the user once. Use static variables to keep track of our state. This will allow us to ignore duplicate alerts. */ if ((m_IPFieldChangeState.IpControl != Ip->hdr.idFrom) || (m_IPFieldChangeState.Field != Ip->iField) || (m_IPFieldChangeState.Value != Ip->iValue) || (m_IPFieldChangeState.RejectTimes > 0)) { m_IPFieldChangeState.RejectTimes = 0; m_IPFieldChangeState.IpControl = Ip->hdr.idFrom; m_IPFieldChangeState.Field = Ip->iField; m_IPFieldChangeState.Value = Ip->iValue; /* Check the field value against its limits. */ if ((Ip->iValue != WLBS_FIELD_EMPTY) && ((Ip->iValue < low) || (Ip->iValue > high))) { /* Alert the user. */ PrintIPRangeError(IDS_PARM_CL_IP_FIELD, Ip->iValue, low, high); TRACE_CRIT("%!FUNC! IP address or subnet mask are not valid and will be rejected"); } } else m_IPFieldChangeState.RejectTimes++; break; default: break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnCheckRct * Description: Called when the user checks/unchecks the remote control enabled checkbox. */ LRESULT CDialogPortRule::OnCheckPortRuleAllVip (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnCheckPortRuleAllVip\n"); switch (wNotifyCode) { case BN_CLICKED: /* If the All Vip box is checked, grey out the IP control, Else brighten the IP control */ if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_PORT_RULE_ALL_VIP)) { ::EnableWindow(::GetDlgItem (m_hWnd, IDC_EDIT_PORT_RULE_VIP), FALSE); } else { ::EnableWindow(::GetDlgItem (m_hWnd, IDC_EDIT_PORT_RULE_VIP), TRUE); } break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnCheckEqual * Description: Called when the user checks/unchecks the equal load weight checkbox. */ LRESULT CDialogPortRule::OnCheckEqual (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnCheckEqual\n"); switch (wNotifyCode) { case BN_CLICKED: /* If equal has been checked, then disable the load weight entry box and spin control. */ if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_EQUAL)) { ::EnableWindow(GetDlgItem(IDC_EDIT_MULTI), FALSE); ::EnableWindow(GetDlgItem(IDC_SPIN_MULTI), FALSE); } else { /* Otherwise, enable them. */ ::EnableWindow(GetDlgItem(IDC_EDIT_MULTI), TRUE); ::EnableWindow(GetDlgItem(IDC_SPIN_MULTI), TRUE); } break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: OnRadioMode * Description: Called when the user changes the radio button selection for the filtering mode. */ LRESULT CDialogPortRule::OnRadioMode (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & fHandled) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::OnRadioMode\n"); switch (wNotifyCode) { case BN_CLICKED: /* Call ModeSwitch to enable/disable UI entities appropriately based on the currently selected filtering mode. */ ModeSwitch(); break; } TRACE_VERB("<-%!FUNC!"); return 0; } /* * Method: PrintRangeError * Description: Displays a message box warning the user of an out-of-range entry. */ void CDialogPortRule::PrintRangeError (unsigned int ids, int low, int high) { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::PrintRangeError\n"); WCHAR szLow[10]; WCHAR szHigh[10]; /* Fill in the allowed range and the offending value. */ wsprintfW(szHigh, L"%d", high); wsprintfW(szLow, L"%d", low); /* Pop-up a message box. */ NcMsgBox(m_hWnd, IDS_PARM_ERROR, ids, MB_APPLMODAL | MB_ICONSTOP | MB_OK, szLow, szHigh); TRACE_VERB("->%!FUNC!"); } /* * Method: ModeSwitch * Description: Called when the user changes the filtering mode. */ VOID CDialogPortRule::ModeSwitch () { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::ModeSwitch\n"); if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_SINGLE)) { /* If single host filtering was selected, then turn on all controls for single host and turn off all controls for multiple host. */ ::EnableWindow(GetDlgItem(IDC_EDIT_SINGLE), TRUE); ::EnableWindow(GetDlgItem(IDC_SPIN_SINGLE), TRUE); ::EnableWindow(GetDlgItem(IDC_EDIT_MULTI), FALSE); ::EnableWindow(GetDlgItem(IDC_SPIN_MULTI), FALSE); ::EnableWindow(GetDlgItem(IDC_CHECK_EQUAL), FALSE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_NONE), FALSE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_SINGLE), FALSE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_CLASSC), FALSE); } else if (::IsDlgButtonChecked(m_hWnd, IDC_RADIO_MULTIPLE)) { /* If multiple host filtering was selected, then turn on all controls for multiple host and turn off all controls for single host. */ ::EnableWindow(GetDlgItem(IDC_EDIT_SINGLE), FALSE); ::EnableWindow(GetDlgItem(IDC_SPIN_SINGLE), FALSE); ::EnableWindow(GetDlgItem(IDC_CHECK_EQUAL), TRUE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_NONE), TRUE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_SINGLE), TRUE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_CLASSC), TRUE); /* Turn the load weight entry on/off depending on the value of the equal load weight checkbox. */ if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_EQUAL)) { ::EnableWindow(GetDlgItem(IDC_EDIT_MULTI), FALSE); ::EnableWindow(GetDlgItem(IDC_SPIN_MULTI), FALSE); } else { ::EnableWindow(GetDlgItem(IDC_EDIT_MULTI), TRUE); ::EnableWindow(GetDlgItem(IDC_SPIN_MULTI), TRUE); } } else { /* Otherwise, if disabled was selected, then turn off all controls for both multiple host and single host. */ ::EnableWindow(GetDlgItem(IDC_EDIT_SINGLE), FALSE); ::EnableWindow(GetDlgItem(IDC_SPIN_SINGLE), FALSE); ::EnableWindow(GetDlgItem(IDC_EDIT_MULTI), FALSE); ::EnableWindow(GetDlgItem(IDC_SPIN_MULTI), FALSE); ::EnableWindow(GetDlgItem(IDC_CHECK_EQUAL), FALSE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_NONE), FALSE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_SINGLE), FALSE); ::EnableWindow(GetDlgItem(IDC_RADIO_AFF_CLASSC), FALSE); } TRACE_VERB("<-%!FUNC!"); } /* * Method: SetInfo * Description: Called to populate the UI with the port rule settings. */ void CDialogPortRule::SetInfo() { TRACE_VERB("->%!FUNC!"); TraceMsg(L"CDialogPortRule::SetInfo\n"); VALID_PORT_RULE * rulep = NULL; DWORD addr[4]; if (m_index != WLBS_INVALID_PORT_RULE_INDEX) { LV_ITEM lvItem; /* Fill in the information necessary to retrieve the port rule data pointer. */ lvItem.iItem = m_index; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; lvItem.state = 0; lvItem.stateMask = 0; /* Get the item from the listbox. */ if (!ListView_GetItem(::GetDlgItem(m_parent->m_hWnd, IDC_LIST_PORT_RULE), &lvItem)) { TraceMsg(L"CDialogPortRule::SetInfo Unable to retrieve item %d from listbox\n", m_index); TRACE_CRIT("%!FUNC! unable to retrieve item %d from listbox", m_index); TRACE_VERB("<-%!FUNC!"); return; } /* Get the data pointer for the i'th port rule in the list. */ if (!(rulep = (VALID_PORT_RULE*)lvItem.lParam)) { TraceMsg(L"CDialogPortRule::SetInfo rule for item %d is bogus\n", m_index); TRACE_CRIT("%!FUNC! rule for item %d is bogus\n", m_index); TRACE_VERB("<-%!FUNC!"); return; } /* Make sure the port rule is valid. This should never happen because invalid rules are not added to the list!!!. */ if (!rulep->valid) { TraceMsg(L"CDialogPortRule::SetInfo Rule %d invalid\n", m_index); TRACE_CRIT("%!FUNC! rule %d invalid\n", m_index); TRACE_VERB("<-%!FUNC!"); return; } /* If the cluster IP address is CVY_ALL_VIP_STRING, grey out the ip control and check the All Vip box, Else, fill in the IP address in the IP control and uncheck the All Vip box */ if (!lstrcmpi(rulep->virtual_ip_addr, CVY_DEF_ALL_VIP)) { /* Grey out IP Control */ ::EnableWindow(::GetDlgItem (m_hWnd, IDC_EDIT_PORT_RULE_VIP), FALSE); /* Check the All Vip checkbox */ ::CheckDlgButton(m_hWnd, IDC_CHECK_PORT_RULE_ALL_VIP, BST_CHECKED); } else { /* Extract the IP address octects from the IP address string. */ GetIPAddressOctets(rulep->virtual_ip_addr, addr); ::SendMessage(::GetDlgItem(m_hWnd, IDC_EDIT_PORT_RULE_VIP), IPM_SETADDRESS, 0, (LPARAM)MAKEIPADDRESS(addr[0], addr[1], addr[2], addr[3])); /* UnCheck the All Vip checkbox */ ::CheckDlgButton(m_hWnd, IDC_CHECK_PORT_RULE_ALL_VIP, BST_UNCHECKED); } /* Set the start and end port values for this rule. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_START, rulep->start_port, FALSE); ::SetDlgItemInt(m_hWnd, IDC_EDIT_END, rulep->end_port, FALSE); /* Check the protocol and filtering mode radio buttons appropriately. */ ::CheckRadioButton(m_hWnd, IDC_RADIO_TCP, IDC_RADIO_BOTH, IDC_RADIO_TCP + rulep->protocol - CVY_MIN_PROTOCOL); ::CheckRadioButton(m_hWnd, IDC_RADIO_SINGLE, IDC_RADIO_DISABLED, IDC_RADIO_SINGLE + rulep->mode - CVY_MIN_MODE); /* Set the default values for filtering mode parameters. Below, we overwrite the ones for the specific filtering mode for this rule. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_SINGLE, CVY_DEF_PRIORITY, FALSE); ::SetDlgItemInt(m_hWnd, IDC_EDIT_MULTI, CVY_DEF_LOAD, FALSE); ::CheckDlgButton(m_hWnd, IDC_CHECK_EQUAL, CVY_DEF_EQUAL_LOAD); ::CheckRadioButton(m_hWnd, IDC_RADIO_AFF_NONE, IDC_RADIO_AFF_CLASSC, IDC_RADIO_AFF_NONE + CVY_DEF_AFFINITY - CVY_MIN_AFFINITY); switch (rulep -> mode) { case CVY_SINGLE: /* In sinlge host filtering, the only user parameter is the priority for this host. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_SINGLE, rulep->mode_data.single.priority, FALSE); break; case CVY_MULTI: /* In multiple host filtering, we need to set the affinity and load weight. */ ::CheckRadioButton(m_hWnd, IDC_RADIO_AFF_NONE, IDC_RADIO_AFF_CLASSC, IDC_RADIO_AFF_NONE + rulep->mode_data.multi.affinity); if (rulep->mode_data.multi.equal_load) { /* If this rule uses equal load, then check the equal checkbox. */ ::CheckDlgButton(m_hWnd, IDC_CHECK_EQUAL, TRUE); } else { /* If this rule has a specific load weight, then uncheck the equal checkbox and set the load value. */ ::CheckDlgButton(m_hWnd, IDC_CHECK_EQUAL, FALSE); ::SetDlgItemInt(m_hWnd, IDC_EDIT_MULTI, rulep->mode_data.multi.load, FALSE); } break; default: /* If the mode is DISABLED, then do nothing. */ break; } } else { /* Grey out IP Control */ ::EnableWindow(::GetDlgItem (m_hWnd, IDC_EDIT_PORT_RULE_VIP), FALSE); /* Check the All Vip checkbox */ ::CheckDlgButton(m_hWnd, IDC_CHECK_PORT_RULE_ALL_VIP, BST_CHECKED); /* Check the radio buttons with their default settings. */ ::CheckRadioButton(m_hWnd, IDC_RADIO_TCP, IDC_RADIO_BOTH, IDC_RADIO_TCP + CVY_DEF_PROTOCOL - CVY_MIN_PROTOCOL); ::CheckRadioButton(m_hWnd, IDC_RADIO_AFF_NONE, IDC_RADIO_AFF_CLASSC, IDC_RADIO_AFF_NONE + CVY_DEF_AFFINITY - CVY_MIN_AFFINITY); ::CheckRadioButton(m_hWnd, IDC_RADIO_SINGLE, IDC_RADIO_DISABLED, IDC_RADIO_SINGLE + CVY_DEF_MODE - CVY_MIN_MODE); /* Check/uncheck the equal load checkbox. */ ::CheckDlgButton(m_hWnd, IDC_CHECK_EQUAL, CVY_DEF_EQUAL_LOAD); /* Fill in the entry boxes with their default values. */ ::SetDlgItemInt(m_hWnd, IDC_EDIT_START, CVY_DEF_PORT_START, FALSE); ::SetDlgItemInt(m_hWnd, IDC_EDIT_END, CVY_DEF_PORT_END, FALSE); ::SetDlgItemInt(m_hWnd, IDC_EDIT_SINGLE, CVY_DEF_PRIORITY, FALSE); ::SetDlgItemInt(m_hWnd, IDC_EDIT_MULTI, CVY_DEF_LOAD, FALSE); } /* Call ModeSwitch to enable and disable UI entries as appropriate, based the the filtering mode currently selected. */ ModeSwitch(); TRACE_VERB("<-%!FUNC!"); }