|
|
/****************************************************************************/ /* robosrv.c */ /* */ /* RoboServer scalability testing utility source file */ /* */ /* Copyright (c) 1999 Microsoft Corporation */ /****************************************************************************/
#ifdef DBG
#define _DEBUG
#endif
#include <windows.h>
#include <winsock2.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <time.h>
#include <tchar.h>
#include <crtdbg.h>
#include "resource.h"
#define SIZEOF_ARRAY(a) (sizeof(a)/sizeof((a)[0]))
// These two window messages are for Windows Sockets messages that we request
// when there are network events
#define WM_SocketRoboClients WM_APP+0
#define WM_SocketQueryIdle WM_APP+1
// This window message is for inter-thread communication from the canary thread
// When there is an error, the canary thread sends this message. wParam is
// a TCHAR pointer that points to the error message to display. lParam is
// unused and must be set to 0.
#define WM_DisplayErrorText WM_APP+2
#define MAX_ROBOCLIENTS 1000
#define MAX_RCNAME 84
#define MAX_STATUS 120
#define MAX_SCRIPTLEN 100
#define MAX_EDIT_TEXT_LENGTH 100
#define MAX_PENDINGINFO 64
#define MAX_DELAYTEXT 8
#define MAX_RECV_CLIENT_DATA 128
#define MAX_NUMBERTEXT 8
#define MAX_TERMSRVRNAME 100
#define MAX_DISPLAY_STRING_LENGTH 200
#define DEBUG_STRING_LEN 200
#define COLUMNONEWIDTH 150
#define COLUMNTWOWIDTH 135
#define COLUMNTHREEWIDTH 45
#define COLUMNFOURWIDTH 150
#define STATE_CONNECTED 1
#define STATE_RUNNING 2
#define STATE_DISCONNECTED 3
#define STATE_PENDING_SCRIPT 4
#define TIMEBUFSIZE 100
#define NUM_TABBED_ITEMS 7
const u_short LISTENER_SOCKET = 9877; const u_short QUERYIDLE_LISTENER_SOCKET = 9878;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
SOCKET SockInit(u_short port);
int DisplayErrorText(TCHAR *psText);
int GetRCIndexFromRCItem(int iRightClickedItem);
int CALLBACK colcmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
int TimedRunScriptOnSelectedItems(HWND hwnd, TCHAR *psScriptName);
int SendRunCommand(int iRCIndex);
int RunCommandOnSelectedItems(HWND hwnd, TCHAR *psCommandName);
int ProcessTimerMessage(HWND hwnd, WPARAM wParam);
int MorePendingScripts();
UINT_PTR MySetTimer(HWND hwnd, UINT_PTR nTimer, UINT nTimeout);
int MyKillTimer(HWND hwnd, UINT_PTR nTimer);
int CancelPendingScripts(HWND hwnd);
int GetRCIndexFromSocket(SOCKET wParam);
int IsDisconnected(TCHAR *psClientName, int *i);
int NumberRunningClients();
int NumClientsPerSet(HWND hwnd);
int GetDelay(HWND hwnd);
int GetSetDelay(HWND hwnd);
void __cdecl CanaryThread(void *unused);
int GetCommandLineArgs(TCHAR *psCommandLine);
int LogToLogFile(char *psLogData);
int ToAnsi(char *psDest, const TCHAR *psSrc, int nSizeOfBuffer);
int CleanUp(HWND hwnd);
void FatalErrMsgBox(HINSTANCE hInstance, UINT nMsgId);
LRESULT CALLBACK TabProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
struct RoboClientData { SOCKET sock; int state; BOOL valid; TCHAR psRCName[MAX_RCNAME]; // The name of this connection
TCHAR psPendingInfo[MAX_PENDINGINFO]; // Will hold the script name
}; typedef struct RoboClientData RoboClientData;
// Globals
RoboClientData g_RCData[MAX_ROBOCLIENTS + 1];
// Queryidle socket
SOCKET g_qidlesock = INVALID_SOCKET; // Listener socket
SOCKET g_listenersocket = INVALID_SOCKET;
// Old procedures for dialog items
LONG_PTR g_OldProc[NUM_TABBED_ITEMS]; // HWNDs for dialog items
HWND g_hwnd[NUM_TABBED_ITEMS];
TCHAR g_TermSrvrName[MAX_TERMSRVRNAME]; TCHAR g_DebugString[DEBUG_STRING_LEN]; char g_DebugStringA[DEBUG_STRING_LEN];
int g_iClientNameColumn; int g_iStatusColumn; int g_iIndexColumn; int g_iTimeStartedColumn; int g_CurrentSortColumn = -1; int g_nNumConnections = 10;
UINT_PTR g_nIDTimer = 1;
HMENU g_hPopupMenu; HANDLE g_hCanaryEvent; HWND g_hListView; HWND g_hNumRunning; HWND g_hTermSrvEditBox; HWND g_hQidleStatus; HWND g_hErrorText; HWND g_hTB; BOOL g_bAscending = FALSE;
CRITICAL_SECTION g_LogFileCritSect;
// WinMain - entry point
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { static TCHAR szAppName[] = _T("RoboServer"); HWND hwnd, hGE, hTSEdit, hDelayEdit, hClientsPerSetEdit; HWND hSetDelayEdit, hCheckBox; MSG msg; WNDCLASSEX wndclass; DWORD x; WORD wVersionRequested; WSADATA wsaData; int err; SOCKET sock; LVCOLUMN lvc; TCHAR * psCommandLine; TCHAR szClientNameColumn[MAX_DISPLAY_STRING_LENGTH]; TCHAR szStatusColumn[MAX_DISPLAY_STRING_LENGTH]; TCHAR szIndexColumn[MAX_DISPLAY_STRING_LENGTH]; TCHAR szStTimeColumn[MAX_DISPLAY_STRING_LENGTH]; TCHAR szDisplayString1[MAX_DISPLAY_STRING_LENGTH]; TCHAR szDisplayString2[MAX_DISPLAY_STRING_LENGTH]; INITCOMMONCONTROLSEX iccex;
lpCmdLine; // unused parameter
hPrevInstance; // unused parameter
LoadString(hInstance, IDS_CLIENTNAMECOL, szClientNameColumn, MAX_DISPLAY_STRING_LENGTH); LoadString(hInstance, IDS_STATUSCOL, szStatusColumn, MAX_DISPLAY_STRING_LENGTH); LoadString(hInstance, IDS_INDEXCOL, szIndexColumn, MAX_DISPLAY_STRING_LENGTH); LoadString(hInstance, IDS_STARTTIMECOL, szStTimeColumn, MAX_DISPLAY_STRING_LENGTH);
wndclass.cbSize = sizeof(wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = DLGWINDOWEXTRA; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON)); if (wndclass.hIcon == 0) { FatalErrMsgBox(hInstance, IDS_LOADICONFAILED); return -1; } wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); if (wndclass.hCursor == 0) { FatalErrMsgBox(hInstance, IDS_LOADCURSORFAILED); return -1; } wndclass.hbrBackground = (HBRUSH) (COLOR_ACTIVEBORDER + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; wndclass.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON)); if (wndclass.hIconSm == 0) { FatalErrMsgBox(hInstance, IDS_LOADSMICONFAILED); return -1; }
// Default value for the terminal server to hit
LoadString(hInstance, IDS_LABTS, szDisplayString1, MAX_DISPLAY_STRING_LENGTH); _tcsncpy(g_TermSrvrName, szDisplayString1, SIZEOF_ARRAY(g_TermSrvrName)); g_TermSrvrName[SIZEOF_ARRAY(g_TermSrvrName) - 1] = 0;
psCommandLine = GetCommandLine();
if (psCommandLine == 0) { FatalErrMsgBox(hInstance, IDS_COMMANDLINEERR); return -1; } if (GetCommandLineArgs(psCommandLine) != 0) return -1;
// Initialize common controls
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS; if (InitCommonControlsEx(&iccex) == FALSE) { FatalErrMsgBox(hInstance, IDS_INITCOMCTRLFAIL); }
if (RegisterClassEx(&wndclass) == 0) { FatalErrMsgBox(hInstance, IDS_REGWNDCLASSFAIL); return -1; }
hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), 0, NULL);
if (hwnd == 0) { FatalErrMsgBox(hInstance, IDS_CREATEMAINWNDERR); return -1; }
wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { FatalErrMsgBox(hInstance, IDS_WINSOCKERR); return -1; }
// Initialize incoming socket
sock = SockInit(LISTENER_SOCKET);
if (WSAAsyncSelect(sock, hwnd, WM_SocketRoboClients, FD_ACCEPT | FD_CONNECT) != 0) { FatalErrMsgBox(hInstance, IDS_WSAASYNCSELERR); goto bad; }
// Initialize queryidle incoming socket
sock = SockInit(QUERYIDLE_LISTENER_SOCKET);
if (WSAAsyncSelect(sock, hwnd, WM_SocketQueryIdle, FD_ACCEPT | FD_CONNECT) != 0) { FatalErrMsgBox(hInstance, IDS_WSAASYNCSELERR); goto bad; }
// store the listener socket for later use
g_listenersocket = sock; memset(g_RCData, 0, sizeof(RoboClientData) * MAX_ROBOCLIENTS);
ShowWindow(hwnd, nCmdShow);
g_hNumRunning = GetDlgItem(hwnd, IDC_NUMTOTAL); g_hQidleStatus = GetDlgItem(hwnd, IDC_STATIC3); g_hErrorText = GetDlgItem(hwnd, IDC_ERRORTEXT); g_hListView = GetDlgItem(hwnd, IDC_LISTVIEW); g_hTermSrvEditBox = GetDlgItem(hwnd, IDC_TERMSRVEDIT); g_hTB = GetDlgItem(hwnd, IDC_SLIDER1);
hTSEdit = GetDlgItem(hwnd, IDC_TERMSRVEDIT); hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT); hClientsPerSetEdit = GetDlgItem(hwnd, IDC_CLIENTSPERSET); hSetDelayEdit = GetDlgItem(hwnd, IDC_SETDELAY);
_ASSERTE(IsWindow(g_hNumRunning)); _ASSERTE(IsWindow(g_hQidleStatus)); _ASSERTE(IsWindow(g_hErrorText)); _ASSERTE(IsWindow(g_hListView)); _ASSERTE(IsWindow(g_hTermSrvEditBox)); _ASSERTE(IsWindow(g_hTB)); _ASSERTE(IsWindow(hTSEdit)); _ASSERTE(IsWindow(hDelayEdit)); _ASSERTE(IsWindow(hClientsPerSetEdit)); _ASSERTE(IsWindow(hSetDelayEdit));
lvc.mask = LVCF_TEXT | LVCF_WIDTH;
lvc.pszText = szClientNameColumn; lvc.cchTextMax = sizeof(szClientNameColumn); lvc.cx = COLUMNONEWIDTH; g_iClientNameColumn = ListView_InsertColumn(g_hListView, 1, &lvc);
lvc.pszText = szStatusColumn; lvc.cchTextMax = sizeof(szStatusColumn); lvc.cx = COLUMNTWOWIDTH; g_iStatusColumn = ListView_InsertColumn(g_hListView, 2, &lvc);
lvc.pszText = szIndexColumn; lvc.cchTextMax = sizeof(szIndexColumn); lvc.cx = COLUMNTHREEWIDTH; g_iIndexColumn = ListView_InsertColumn(g_hListView, 3, &lvc);
lvc.pszText = szStTimeColumn; lvc.cchTextMax = sizeof(szStTimeColumn); lvc.cx = COLUMNFOURWIDTH; g_iTimeStartedColumn = ListView_InsertColumn(g_hListView, 4, &lvc);
LoadString(hInstance, IDS_WELCOME, szDisplayString1, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString1); SetWindowText(hTSEdit, g_TermSrvrName); SetWindowText(hDelayEdit, _T("30")); SetWindowText(hClientsPerSetEdit, _T("10")); SetWindowText(hSetDelayEdit, _T("15"));
// Initialize Graphic Equalizer
hGE = GetDlgItem(hwnd, IDC_PROGRESS1); _ASSERTE(IsWindow(hGE)); SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10)); SendMessage(hGE, PBM_SETPOS, 8, 0);
hGE = GetDlgItem(hwnd, IDC_PROGRESS2); _ASSERTE(IsWindow(hGE)); SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10)); SendMessage(hGE, PBM_SETPOS, 7, 0);
hGE = GetDlgItem(hwnd, IDC_PROGRESS3); _ASSERTE(IsWindow(hGE)); SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10)); SendMessage(hGE, PBM_SETPOS, 6, 0);
hGE = GetDlgItem(hwnd, IDC_PROGRESS4); _ASSERTE(IsWindow(hGE)); SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10)); SendMessage(hGE, PBM_SETPOS, 6, 0);
hGE = GetDlgItem(hwnd, IDC_PROGRESS5); _ASSERTE(IsWindow(hGE)); SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10)); SendMessage(hGE, PBM_SETPOS, 7, 0);
hGE = GetDlgItem(hwnd, IDC_PROGRESS6); _ASSERTE(IsWindow(hGE)); SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10)); SendMessage(hGE, PBM_SETPOS, 8, 0);
// Initialize Slider control IDC_SLIDER1 for number of RC connections
// per client
{ TCHAR buffer[6]; SendMessage(g_hTB, TBM_SETRANGE, (WPARAM) (BOOL) TRUE, (LPARAM) MAKELONG(1, 20)); SendMessage(g_hTB, TBM_SETTICFREQ, (WPARAM) 1, (LPARAM) 0); SendMessage(g_hTB, TBM_SETSEL, (WPARAM) (BOOL) TRUE, MAKELONG(1, g_nNumConnections)); // Now set the number to "M"
_stprintf(buffer, _T("%d"), 20); SetWindowText(GetDlgItem(hwnd, IDC_STATIC6), buffer); }
// make number of connections a command line param
SendMessage(g_hTB, TBM_SETPOS, (WPARAM) (BOOL) TRUE, (LPARAM) g_nNumConnections);
// Initialize check box
hCheckBox = GetDlgItem(hwnd, IDC_CANARYCHECK); _ASSERTE(IsWindow(hCheckBox)); SendMessage(hCheckBox, BM_SETCHECK, BST_CHECKED, 0);
// Clear qidle status
SetWindowText(g_hQidleStatus, _T(""));
g_hPopupMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)); if (g_hPopupMenu == 0) { LoadString(hInstance, IDS_POPUPMENULOADERR, szDisplayString1, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString1); } g_hPopupMenu = GetSubMenu(g_hPopupMenu, 0);
// Initialize critical section for log file
InitializeCriticalSection(&g_LogFileCritSect);
// Initialize everything required for canary thread, and then create the
// canary thread first, create auto-reset, doesn't start in signaled state
// event
if ((g_hCanaryEvent = CreateEvent(0, FALSE, FALSE, NULL)) == NULL) { FatalErrMsgBox(hInstance, IDS_CANARYEVENTERR); goto bad; } if (_beginthread(CanaryThread, 0, hwnd) == -1) { FatalErrMsgBox(hInstance, IDS_CANARYTHREADERR); goto bad; }
_ASSERTE(SetFocus(g_hListView) != NULL);
// Store old window procedures for controls so that I can subclass them
// Also, store the HWND of each control for searching
g_OldProc[0] = SetWindowLongPtr(g_hListView, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[0] = g_hListView; g_OldProc[1] = SetWindowLongPtr(g_hTB, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[1] = g_hTB; g_OldProc[2] = SetWindowLongPtr(hCheckBox, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[2] = hCheckBox; g_OldProc[3] = SetWindowLongPtr(g_hTermSrvEditBox, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[3] = g_hTermSrvEditBox; g_OldProc[4] = SetWindowLongPtr(hClientsPerSetEdit, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[4] = hClientsPerSetEdit; g_OldProc[5] = SetWindowLongPtr(hDelayEdit, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[5] = hDelayEdit; g_OldProc[6] = SetWindowLongPtr(hSetDelayEdit, GWLP_WNDPROC, (LONG_PTR) TabProc); g_hwnd[6] = hSetDelayEdit;
_ASSERTE(g_OldProc[0] != 0); _ASSERTE(g_OldProc[1] != 0); _ASSERTE(g_OldProc[2] != 0); _ASSERTE(g_OldProc[3] != 0); _ASSERTE(g_OldProc[4] != 0); _ASSERTE(g_OldProc[5] != 0); _ASSERTE(g_OldProc[6] != 0);
while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return (int) msg.wParam;
bad: WSACleanup(); return 0;
}
// receives window messages and deals with them
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { TCHAR szDisplayString[MAX_DISPLAY_STRING_LENGTH];
switch (iMsg) { case WM_DESTROY: // Close all open connections
CleanUp(hwnd); PostQuitMessage(0); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_RUNSCRIPT_KNOWLEDGEWORKER: TimedRunScriptOnSelectedItems(hwnd, _T("KnowWkr")); break; case ID_RUNSCRIPT_KNOWLEDGEWORKERFAST: TimedRunScriptOnSelectedItems(hwnd, _T("FastKW")); break; case ID_RUNSCRIPT_ADMINISTRATIVEWORKER: TimedRunScriptOnSelectedItems(hwnd, _T("AdminWkr")); break; case ID__RUNSCRIPT_DATA: TimedRunScriptOnSelectedItems(hwnd, _T("taskwkr")); break; case ID__RUNSCRIPT_STW: TimedRunScriptOnSelectedItems(hwnd, _T("stw")); break; case ID__RUNSCRIPT_HPW: TimedRunScriptOnSelectedItems(hwnd, _T("hpw")); break; case ID__RUNSCRIPT_BLANK: TimedRunScriptOnSelectedItems(hwnd, _T("blank")); break; case ID__RUNSCRIPT_CONFIGURATIONSCRIPT: TimedRunScriptOnSelectedItems(hwnd, _T("config")); break; case ID__UPDATE: RunCommandOnSelectedItems(hwnd, _T("update")); break; case ID__REBOOT: RunCommandOnSelectedItems(hwnd, _T("reboot")); break; case ID_CANCEL: CancelPendingScripts(hwnd); break; default: OutputDebugString(_T("Unhandled WM_COMMAND: ")); wsprintf(g_DebugString, _T("%d\n"), LOWORD(wParam)); OutputDebugString(g_DebugString); break; } break; case WM_CREATE: break; case WM_CHAR: break; case WM_TIMER: ProcessTimerMessage(hwnd, wParam); return 0; case WM_KEYDOWN: // NOTE INTENTIONAL FALLTHROUGH!
case WM_SYSKEYDOWN: if (wParam == VK_TAB) { SetFocus(g_hwnd[0]); } break; case WM_DisplayErrorText: return DisplayErrorText((TCHAR *) wParam); case WM_NOTIFY: { switch (((LPNMHDR) lParam)->code) { case NM_RCLICK: { POINT pnt;
if (ListView_GetSelectedCount(g_hListView) > 0) { GetCursorPos(&pnt);
TrackPopupMenu(g_hPopupMenu, 0, pnt.x, pnt.y, 0, hwnd, 0); } } break; case LVN_ODCACHEHINT: break; case LVN_COLUMNCLICK: if (g_CurrentSortColumn == ((LPNMLISTVIEW)lParam)->iSubItem) g_bAscending = !g_bAscending; else g_bAscending = TRUE;
g_CurrentSortColumn = ((LPNMLISTVIEW)lParam)->iSubItem;
if (ListView_SortItems(g_hListView, colcmp, ((LPNMLISTVIEW)lParam)->iSubItem) == FALSE) OutputDebugString(_T("Sort failed")); break;
default: break; } } break; // WM_SocketQueryIdle is the window message that we are going to request
// for all information that originates from the queryidle utility. This
// utility will provide information about what user numbers to re-run as
// well as when retry limits have been exceeded
// line protocol (strings are ASCII and null-terminated):
// queryidle sends "restart xxx", where xxx is the 1-indexed number of the
// session to be restarted
// queryidle sends "frqfail xxx", where xxx is the 1-indexed number of
// the user session for the status line
case WM_SocketQueryIdle: switch (WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: { struct sockaddr_in SockAddr; int SockAddrLen;
g_qidlesock = accept(wParam, (struct sockaddr *) &SockAddr, &SockAddrLen);
if (g_qidlesock == INVALID_SOCKET) { LoadString(NULL, IDS_INVALIDQIDLESOCKET, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); return TRUE; }
if (WSAAsyncSelect(g_qidlesock, hwnd, WM_SocketQueryIdle, FD_CLOSE | FD_READ) != 0) { LoadString(NULL, IDS_WSAASYNCQIDLEERR, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); return TRUE; }
LoadString(NULL, IDS_QIDLECONNEST, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); return TRUE; } break; case FD_READ: { unsigned n; char psData[MAX_RECV_CLIENT_DATA];
// SetWindowText(g_hQidleStatus, _T("Qidle data received"));
n = recv(g_qidlesock, psData, sizeof(psData), 0);
if (n != SOCKET_ERROR) { if ((n == strlen("restart xxx") + 1) || (n == strlen("idle xxx") + 1)) { // get the number of the connection in question (xxx)
int nUser;
// if it's a restart command
if (strncmp(psData, "restart ", strlen("restart ")) == 0) {
nUser = atoi(&psData[8]); // restart the given session if it's already running
if (g_RCData[nUser - 1].state == STATE_RUNNING) { SendRunCommand(nUser - 1); } else { LoadString(NULL, IDS_QIDLEREPORTWEIRDUSER, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); } _snprintf(g_DebugStringA, DEBUG_STRING_LEN, "Queryidle indicated that" " user smc%03d failed.", nUser); LogToLogFile(g_DebugStringA); break; } // if it's the frqfail command
if (strncmp(psData, "frqfail ", strlen("frqfail ")) == 0) {
nUser = atoi(&psData[8]); // set the status to the fact that xxx
// is frequently failing
wsprintf(g_DebugString, _T("User smc%03d has failed ") _T("to run correctly for too long and will ") _T("be logged off"), nUser); SetWindowText(g_hQidleStatus, g_DebugString); ToAnsi(g_DebugStringA, g_DebugString, DEBUG_STRING_LEN); LogToLogFile(g_DebugStringA); break; } // if it's the idle notification
if (strncmp(psData, "idle ", strlen("idle ")) == 0) { LoadString(NULL, IDS_USERISIDLE, szDisplayString, MAX_DISPLAY_STRING_LENGTH); // I think this is fixed now, but haven't tested
nUser = atoi(&psData[5]); wsprintf(g_DebugString, szDisplayString, nUser); SetWindowText(g_hQidleStatus, g_DebugString); ToAnsi(g_DebugStringA, g_DebugString, DEBUG_STRING_LEN); LogToLogFile(g_DebugStringA); break; } // else display an error
LoadString(NULL, IDS_QIDLESENTGIBBERISH, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); } else { LoadString(NULL, IDS_QIDLESENTWRONGLENGTH, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); }
} else { LoadString(NULL, IDS_QIDLESOCKERR, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); } return TRUE; } break; case FD_CLOSE: { LoadString(NULL, IDS_QIDLESAYSGOODBYE, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hQidleStatus, szDisplayString); return TRUE; } break; } break; case WM_SocketRoboClients: switch (WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: { struct sockaddr_in SockAddr; int SockAddrLen, i, iItemIndex; HWND hTB; TCHAR psSockAppend[9]; // ".(.....)" + 1
char psNumConnections[2]; // one char null terminated
TCHAR psIndex[5]; // up to 4 digits + null
TCHAR psClientName[MAX_RCNAME]; char psClientNameA[MAX_RCNAME]; int nSliderPos; SOCKET sock; struct hostent * he; LVITEM lvi;
LoadString(NULL, IDS_PROCESSINGCONNREQ, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString);
SockAddrLen = sizeof(SockAddr);
sock = accept(wParam, (struct sockaddr *) &SockAddr, &SockAddrLen);
// gethostbyaddr tries to confuse us by taking a char * when
// it really wants this peculiar sin_addr thing
// The second argument to this function ("4") is the length of
// the address.
he = gethostbyaddr((char *)&SockAddr.sin_addr, 4, AF_INET); if (he == NULL) { LoadString(NULL, IDS_GETHOSTFAILED, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString); return FALSE; }
strcpy(psClientNameA, he->h_name); #ifdef UNICODE
MultiByteToWideChar(CP_ACP, 0, psClientNameA, -1, psClientName, MAX_RCNAME); #else
strcpy(psClientName, psClientNameA); #endif
_tcstok(psClientName, _T(".")); // Kill domain
// See if there is a disconnected client by that name
if (IsDisconnected(psClientName, &i)) {
// Good--we've found one--remove that list item now
LVFINDINFO lvfi; int iListViewIndex;
lvfi.flags = LVFI_STRING; lvfi.psz = g_RCData[i].psRCName; lvfi.lParam = 0; lvfi.vkDirection = 0; iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi); if (ListView_DeleteItem(g_hListView, iListViewIndex) == FALSE) { LoadString(NULL, IDS_COULDNOTDELITEM, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString); } } else {
// Find a spot in our g_RCData array
for (i = 0; i < MAX_ROBOCLIENTS; i++) if (g_RCData[i].valid == FALSE) break; }
g_RCData[i].valid = TRUE; g_RCData[i].sock = sock;
LoadString(NULL, IDS_CLIENTCONNECTED, szDisplayString, MAX_DISPLAY_STRING_LENGTH); wsprintf(g_DebugString, szDisplayString, i + 1); SetWindowText(g_hErrorText, g_DebugString);
if (g_RCData[i].sock == INVALID_SOCKET) { LoadString(NULL, IDS_INVALIDSOCKETFROMACCEPT, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString); g_RCData[i].valid = FALSE; return FALSE; }
// Send it the number of connections it is to make
// Determine the position of the slider control
nSliderPos = (int) SendMessage(g_hTB, TBM_GETPOS, 0, 0); psNumConnections[0] = (char) (nSliderPos + '0'); psNumConnections[1] = 0; // null terminate
if (send(g_RCData[i].sock, psNumConnections, sizeof(psNumConnections), 0) == SOCKET_ERROR) { LoadString(NULL, IDS_SENDERRNUMCONN, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString); return FALSE; }
// Add the incoming connection to the list box
// this won't append a null if count is less than psClientName,
// which is bad
_tcsncpy(g_RCData[i].psRCName, psClientName, MAX_RCNAME - _tcslen(_T(" (%d)")) - 1); // clean up display a bit
_tcstok(g_RCData[i].psRCName, _T("."));
// add socket number to entry for multiplexing
_sntprintf(psSockAppend, 9, _T(" (%d)"), g_RCData[i].sock); _tcscat(g_RCData[i].psRCName, psSockAppend);
// create the actual list view item
lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = (int) SendMessage(g_hListView, LVM_GETITEMCOUNT, 0, 0); lvi.iSubItem = 0; lvi.pszText = g_RCData[i].psRCName; lvi.cchTextMax = sizeof(g_RCData[i].psRCName); lvi.lParam = (LPARAM) (char *)g_RCData[i].psRCName; iItemIndex = ListView_InsertItem(g_hListView, &lvi);
g_RCData[i].state = STATE_CONNECTED; LoadString(NULL, IDS_CONNECTED, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, szDisplayString);
// set the index field
wsprintf(psIndex, _T("%03d"), i + 1); ListView_SetItemText(g_hListView, iItemIndex, g_iIndexColumn, psIndex);
// Now set up notification for this socket
if (WSAAsyncSelect(g_RCData[i].sock, hwnd, WM_SocketRoboClients, FD_CLOSE | FD_READ) != SOCKET_ERROR) { return TRUE; } else { LoadString(NULL, IDS_ERRORCANTRECVNOTIFICATIONS, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, szDisplayString); return TRUE; } } case FD_CONNECT: // MessageBox(0, _T("Error"), _T("Received connect unexpectedly"), 0);
break; case FD_CLOSE: { int i; int iListViewIndex; LVFINDINFO lvfi; TCHAR psNumberText[MAX_NUMBERTEXT];
LoadString(NULL, IDS_ROBOCLIDISCON, szDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, szDisplayString);
// find the entry that corresponds to our socket
i = GetRCIndexFromSocket(wParam);
// Find the spot in the ListView that has this Client Name
lvfi.flags = LVFI_STRING; lvfi.psz = g_RCData[i].psRCName; lvfi.lParam = 0; lvfi.vkDirection = 0; iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi);
g_RCData[i].state = STATE_DISCONNECTED;
// wsprintf(debugString, "Deleting socket %d from index %d of g_RCData[] (%s)", wParam,
// i, g_RCData[i].psRCName);
// SetWindowText(hErrorText, debugString);
// Update number running
wsprintf(psNumberText, _T("%d"), NumberRunningClients()); SetWindowText(g_hNumRunning, psNumberText);
// Set text of column to "Lost Connection"
LoadString(NULL, IDS_LOSTCONNECTION, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iListViewIndex, g_iStatusColumn, szDisplayString); // Erase the time started column
ListView_SetItemText(g_hListView, iListViewIndex, g_iTimeStartedColumn, _T(""));
} break; case FD_READ: { int iRCIndex, n, iListViewIndex; char psData[MAX_RECV_CLIENT_DATA]; LVFINDINFO lvfi; iRCIndex = GetRCIndexFromSocket(wParam);
n = recv(g_RCData[iRCIndex].sock, psData, sizeof(psData), 0);
if (n == SOCKET_ERROR) { OutputDebugString(_T("FD_READ but SOCKET_ERROR on recv")); } else { lvfi.flags = LVFI_STRING; lvfi.psz = g_RCData[iRCIndex].psRCName; lvfi.lParam = 0; lvfi.vkDirection = 0; iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi); if (strncmp(psData, "errorsmclient", (n > 13) ? 13 : n) == 0) { LoadString(NULL, IDS_SMCLIENTRUNERR, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iListViewIndex, g_iStatusColumn, szDisplayString); } else if (strncmp(psData, "errorcreate", (n > 11) ? 11 : n) == 0) { LoadString(NULL, IDS_CREATESCRERR, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iListViewIndex, g_iStatusColumn, szDisplayString); } else if (strncmp(psData, "success", (n > 11) ? 11 : n) == 0) {
SYSTEMTIME startloctime; TCHAR psStartTimeDatePart[TIMEBUFSIZE]; TCHAR psStartTimeTimePart[TIMEBUFSIZE]; TCHAR psStartTime[TIMEBUFSIZE * 2];
GetLocalTime(&startloctime); // set starttime
GetDateFormat(0, 0, &startloctime, 0, psStartTimeDatePart, TIMEBUFSIZE); GetTimeFormat(0, 0, &startloctime, 0, psStartTimeTimePart, TIMEBUFSIZE);
wsprintf(psStartTime, _T("%s %s"), psStartTimeDatePart, psStartTimeTimePart);
ListView_SetItemText(g_hListView, iListViewIndex, g_iTimeStartedColumn, psStartTime); LoadString(NULL, IDS_SCRIPTSTARTED, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iListViewIndex, g_iStatusColumn, szDisplayString); } else { LoadString(NULL, IDS_UNKNOWNROBOTALK, szDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iListViewIndex, g_iStatusColumn, szDisplayString); } } } break; } break; }
return DefWindowProc(hwnd, iMsg, wParam, lParam); }
// The canary architecture works like this: The canary thread (i.e., this
// function) is spawned when the application initializes, and immediately
// blocks on g_hCanaryEvent. The main app, when it is time for the canary
// to run, signals the event. Then the canary blocks on the timer script
// (called "canary" so it can be a "canary.cmd," a "canary.bat," a
// "canary.exe," etc.), writes how long it took to a file, and then blocks
// again.
void __cdecl CanaryThread(void *unused) { HWND hwnd = (HWND) unused; HWND hButton; int bCheck; FILE *fp; SYSTEMTIME timelocinit; SYSTEMTIME timelocfin; FILETIME ftinit; FILETIME ftfin; ULARGE_INTEGER nInit; ULARGE_INTEGER nFin; ULARGE_INTEGER nDiffTime; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH]; TCHAR psNumRunning[MAX_NUMBERTEXT]; TCHAR psTimeDatePart[TIMEBUFSIZE]; TCHAR psTimeTimePart[TIMEBUFSIZE]; char psNumRunningA[MAX_NUMBERTEXT]; char psTimeDatePartA[TIMEBUFSIZE]; char psTimeTimePartA[TIMEBUFSIZE];
hButton = GetDlgItem(hwnd, IDC_CANARYCHECK);
for( ; ; ) { WaitForSingleObject(g_hCanaryEvent, INFINITE);
// Check checkbox to see if "run canary automatically" is on
// IDC_CANARYCHECK
bCheck = (int) SendMessage(hButton, BM_GETCHECK, 0, 0); if (bCheck != 0) { // FUNCTIONALITY CHANGE: Canary delays the delay between
// multiselect commands before starting
LoadString(NULL, IDS_CANARYDELAYING, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString, 0); Sleep(GetDelay(hwnd)); LoadString(NULL, IDS_CANARYSTARTING, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString, 0); // Get the time
GetLocalTime(&timelocinit); // Get number of scripts attempted
GetWindowText(g_hNumRunning, psNumRunning, MAX_NUMBERTEXT); // run the script
if (_spawnl(_P_WAIT, "canary", "canary", 0) != 0) { LoadString(NULL, IDS_CANARYCOULDNTSTART, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString, 0); } else { LoadString(NULL, IDS_CANARYFINISHED, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString, 0); } // Get the time again
GetLocalTime(&timelocfin); // compute difference
if ( SystemTimeToFileTime(&timelocinit, &ftinit) && SystemTimeToFileTime(&timelocfin, &ftfin) ) {
memcpy(&nInit, &ftinit, sizeof(FILETIME)); memcpy(&nFin, &ftfin, sizeof(FILETIME)); // This gives the difference in 100-nanosecond intervals (10^-7 sec).
nDiffTime.QuadPart = nFin.QuadPart - nInit.QuadPart; // Divide by 10^7 to get seconds
nDiffTime.QuadPart /= 10000000; // Get the date and time strings
GetDateFormat(0, 0, &timelocinit, 0, psTimeDatePart, TIMEBUFSIZE); GetTimeFormat(0, 0, &timelocinit, 0, psTimeTimePart, TIMEBUFSIZE); // Convert strings to ANSI
#ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, psTimeDatePart, -1, psTimeDatePartA, TIMEBUFSIZE, 0, 0); WideCharToMultiByte(CP_ACP, 0, psTimeTimePart, -1, psTimeTimePartA, TIMEBUFSIZE, 0, 0); WideCharToMultiByte(CP_ACP, 0, psNumRunning, -1, psNumRunningA, MAX_NUMBERTEXT, 0, 0); #else
strncpy(psTimeDatePartA, psTimeDatePart, TIMEBUFSIZE); strncpy(psTimeTimePartA, psTimeTimePart, TIMEBUFSIZE); strncpy(psNumRunningA, psNumRunning, MAX_NUMBERTEXT); #endif
// open the file
fp = fopen("canary.csv", "a+t"); // write the difference to the file
if (fp != 0) { fprintf(fp, "%s %s,%s,%d:%02d\n", psTimeDatePartA, psTimeTimePartA, psNumRunningA, (int) nDiffTime.QuadPart / 60, (int) nDiffTime.QuadPart % 60); // close the file
fclose(fp); } else { LoadString(NULL, IDS_CANARYCOULDNOTOPENFILE, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString, 0); } } } } }
// This function displays text in the status line. Returns 0 on success,
// nonzero on error.
int DisplayErrorText(TCHAR *psText) { SetWindowText(g_hErrorText, psText); return 0; }
// helper function to find out the index in our data structure from the
// incoming socket
int GetRCIndexFromSocket(SOCKET wParam) {
int i;
for (i = 0; i < MAX_ROBOCLIENTS; i++) { if (g_RCData[i].valid == TRUE) if (g_RCData[i].sock == wParam) break; }
return i; }
// Initialize the listener socket
SOCKET SockInit(u_short port) { SOCKET listenfd; struct sockaddr_in servaddr; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH]; TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == INVALID_SOCKET) { LoadString(NULL, IDS_SOCKETERROR, psDisplayTitleString, MAX_DISPLAY_STRING_LENGTH); LoadString(NULL, IDS_SOCKETERROR, psDisplayString, MAX_DISPLAY_STRING_LENGTH); MessageBox(0, psDisplayString, psDisplayTitleString, 0); goto err; }
memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) { LoadString(NULL, IDS_BINDERRTITLE, psDisplayTitleString, MAX_DISPLAY_STRING_LENGTH); LoadString(NULL, IDS_BINDERRBODY, psDisplayString, MAX_DISPLAY_STRING_LENGTH); MessageBox(0, psDisplayString, psDisplayTitleString, 0); goto err; }
if (listen(listenfd, SOMAXCONN) != 0) { LoadString(NULL, IDS_LISTENERROR, psDisplayTitleString, MAX_DISPLAY_STRING_LENGTH); LoadString(NULL, IDS_LISTENERROR, psDisplayString, MAX_DISPLAY_STRING_LENGTH); MessageBox(0, psDisplayString, psDisplayTitleString, 0); goto err; }
return listenfd;
err: return INVALID_SOCKET; }
// function needed for ListView_SortItems to work. Compares the values
// in two columns.
int CALLBACK colcmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamColumn) { TCHAR *psz1; TCHAR *psz2; int i1, i2; TCHAR pszClientName[MAX_RCNAME]; TCHAR pszSubItem1[MAX_RCNAME]; TCHAR pszSubItem2[MAX_RCNAME];
psz1 = (TCHAR *) lParam1; psz2 = (TCHAR *) lParam2;
if ((lParam1 == 0) || (lParam2 == 0)) { OutputDebugString(_T("a null was passed to the sort function")); return 0; }
// Find the item number in the ListView
for (i1 = 0; i1 < ListView_GetItemCount(g_hListView); i1++) { ListView_GetItemText(g_hListView, i1, g_iClientNameColumn, pszClientName, MAX_RCNAME); if (_tcscmp(psz1, pszClientName) == 0) break; } for (i2 = 0; i2 < ListView_GetItemCount(g_hListView); i2++) { ListView_GetItemText(g_hListView, i2, g_iClientNameColumn, pszClientName, MAX_RCNAME); if (_tcscmp(psz2, pszClientName) == 0) break; } ListView_GetItemText(g_hListView, i1, (int) lParamColumn, pszSubItem1, MAX_RCNAME); ListView_GetItemText(g_hListView, i2, (int) lParamColumn, pszSubItem2, MAX_RCNAME);
if (g_bAscending == TRUE) return _tcscmp(pszSubItem1, pszSubItem2); else return -_tcscmp(pszSubItem1, pszSubItem2);
}
// Get the RoboClient index (in our data structure) from an entry in the
// listview (called an item)
int GetRCIndexFromRCItem(int iRightClickedItem) { int i; TCHAR psItemText[MAX_RCNAME];
for (i = 0; i < MAX_ROBOCLIENTS; i++) { if (g_RCData[i].valid == TRUE) { ListView_GetItemText(g_hListView, iRightClickedItem, g_iClientNameColumn, psItemText, MAX_RCNAME); if (_tcscmp(g_RCData[i].psRCName, psItemText) == 0) break; } }
return i; }
// Initiates a script run for a particular scriptname passed in
int TimedRunScriptOnSelectedItems(HWND hwnd, TCHAR *psScriptName) {
int iItemIndex; int iRCIndex; int nTimeout; int bCheck; HWND hDelayEdit; HWND hButton; LVITEM lvi; TCHAR psDelayText[MAX_DELAYTEXT]; TCHAR psTempString[MAX_DISPLAY_STRING_LENGTH]; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
hButton = GetDlgItem(hwnd, IDC_CANARYCHECK); _ASSERTE(IsWindow(hButton));
// Loop through all the items in the list, changing the ones
// that are selected to "Pending" and STATE_PENDING
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView); iItemIndex++) { lvi.iItem = iItemIndex; lvi.iSubItem = 0; lvi.mask = LVIF_STATE; lvi.stateMask = LVIS_SELECTED; ListView_GetItem(g_hListView, &lvi); if (lvi.state & LVIS_SELECTED) { iRCIndex = GetRCIndexFromRCItem(iItemIndex); if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) { LoadString(NULL, IDS_PENDING, psTempString, MAX_DISPLAY_STRING_LENGTH); _sntprintf(psDisplayString, MAX_DISPLAY_STRING_LENGTH, psTempString, psScriptName); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psDisplayString); g_RCData[iRCIndex].state = STATE_PENDING_SCRIPT; _tcsncpy(g_RCData[iRCIndex].psPendingInfo, psScriptName, MAX_PENDINGINFO); } else { LoadString(NULL, IDS_CANTRUNDISC, psTempString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psTempString); } } }
// Now, set the timer for all of the items.
hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT); _ASSERTE(IsWindow(hDelayEdit)); GetWindowText(hDelayEdit, psDelayText, MAX_DELAYTEXT);
nTimeout = _ttoi(psDelayText); nTimeout *= 1000;
// this should probably be a ui thing rather than a silent sfp-like thing
if (nTimeout == 0) nTimeout = 100; // Don't allow a delay of 0
// Only delay if the "Run canary automatically" button is checked
// Check checkbox to see if "run canary automatically" is on
// IDC_CANARYCHECK
bCheck = (int) SendMessage(hButton, BM_GETCHECK, 0, 0); if (bCheck != 0) { g_nIDTimer = MySetTimer(hwnd, g_nIDTimer, GetSetDelay(hwnd)); } else { g_nIDTimer = MySetTimer(hwnd, g_nIDTimer, 0); }
SetEvent(g_hCanaryEvent); // Fire off a WM_TIMER message immediately for the first guy
// SendMessage(hwnd, WM_TIMER, g_nIDTimer, 0);
return 0; }
// Tell selected roboclients to run batch files such as reboot or update
int RunCommandOnSelectedItems(HWND hwnd, TCHAR *psCommandName) {
char psCommandNameA[MAX_SCRIPTLEN]; int iItemIndex, iRCIndex; LVITEM lvi; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
#ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, psCommandName, -1, psCommandNameA, MAX_SCRIPTLEN, 0, 0); #else
strcpy(psCommandNameA, psCommandName); #endif
// Loop through all the items in the list
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView); iItemIndex++) { lvi.iItem = iItemIndex; lvi.iSubItem = 0; lvi.mask = LVIF_STATE; lvi.stateMask = LVIS_SELECTED; ListView_GetItem(g_hListView, &lvi); if (lvi.state & LVIS_SELECTED) { iRCIndex = GetRCIndexFromRCItem(iItemIndex); if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) { if (send(g_RCData[iRCIndex].sock, psCommandNameA, _tcslen(psCommandName), 0) != SOCKET_ERROR) { LoadString(NULL, IDS_COMMANDSENT, psDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psDisplayString); } else { LoadString(NULL, IDS_SENDERROR, psDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psDisplayString); } } // else was disconnected
} } return 0; }
// main dispatch routine for when a timer message is received
int ProcessTimerMessage(HWND hwnd, WPARAM wParam) { UINT_PTR nTimer = wParam; int iItemIndex; int iRCIndex; TCHAR psNumberText[MAX_NUMBERTEXT];
// I don't know how it happens, but there start to be weird other timers
// about.
if (nTimer != g_nIDTimer) return 0;
// For now, find the first pending item in the list and change its status
// to running
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView); iItemIndex++) { iRCIndex = GetRCIndexFromRCItem(iItemIndex); if (g_RCData[iRCIndex].valid) { if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) {
// Send the command to the client
if (SendRunCommand(iRCIndex) == 0) {
// Update count
wsprintf(psNumberText, _T("%d"), NumberRunningClients()); SetWindowText(g_hNumRunning, psNumberText);
// Fix the timer
// If NumRunning() % NumPerSet() == 0 AND NumRunning != 0,
// Set the timer to SETDELAY * 60 seconds at the end of
// running.
// * NumClientsPerSet was fixed at nonzero when MySetTimer
// was called initially
// * Not using MySetTimer here because that does all sorts
// of unnecessary disables
if (NumberRunningClients() % NumClientsPerSet(hwnd) == 0) { if (NumberRunningClients() != 0) { g_nIDTimer = SetTimer(hwnd, g_nIDTimer, GetSetDelay(hwnd), 0); SetEvent(g_hCanaryEvent); // do the canary thing
} } else { // else set the timer to the normal value. It used to be
// that we would set the timer to the normal value if
// numrunning % numperset was == 1, but that had buggy
// behavior when you canceled when there were a couple
// running and then you ran some more.
// if (NumberRunningClients() % NumClientsPerSet(hwnd) == 1)
g_nIDTimer = SetTimer(hwnd, g_nIDTimer, GetDelay(hwnd), 0); } }
if (MorePendingScripts() == 0) { MyKillTimer(hwnd, g_nIDTimer); }
return 0; } } }
// If we got here, we need to kill the timer
MyKillTimer(hwnd, nTimer);
return 0; }
// Actually send the run command to a particular RC connection.
// Returns 0 on success, nonzero on error
int SendRunCommand(int iRCIndex) {
TCHAR psEditText[MAX_EDIT_TEXT_LENGTH]; TCHAR psCommandText[MAX_SCRIPTLEN]; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH]; char psCommandTextA[MAX_SCRIPTLEN]; int iItemIndex; LVFINDINFO lvfi;
lvfi.flags = LVFI_STRING; lvfi.psz = g_RCData[iRCIndex].psRCName; lvfi.lParam = 0; lvfi.vkDirection = 0; iItemIndex = ListView_FindItem(g_hListView, -1, &lvfi);
GetWindowText(g_hTermSrvEditBox, psEditText, MAX_EDIT_TEXT_LENGTH); wsprintf(psCommandText, _T("%s/%s/smc%03d"), psEditText, g_RCData[iRCIndex].psPendingInfo, iRCIndex + 1);
#ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, psCommandText, -1, psCommandTextA, MAX_SCRIPTLEN, 0, 0); #else
strcpy(psCommandTextA, psCommandText); #endif
if (send(g_RCData[iRCIndex].sock, psCommandTextA, _tcslen(psCommandText), 0) != SOCKET_ERROR) { // if successful, change text to Run command sent
LoadString(NULL, IDS_RUNCOMMANDSENT, psDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psDisplayString);
// change state to RUNNING
g_RCData[iRCIndex].state = STATE_RUNNING;
return 0; } else { LoadString(NULL, IDS_SENDERROR, psDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psDisplayString);
return -1; }
}
// In: i, uninitialized integer
// psClientName, Client to try to find in the list
// Out: i, RCindex of a disconnected session with name "psClientName"
// Returns: 1 if found a disconnected item with that name,
// 0 otherwise
int IsDisconnected(TCHAR *psClientName, int *iReturnedIndex) { int i; for (i = 0; i < MAX_ROBOCLIENTS; i++) { if (g_RCData[i].valid == TRUE) if (g_RCData[i].state == STATE_DISCONNECTED) if (_tcsncmp(psClientName, g_RCData[i].psRCName, _tcslen(psClientName)) == 0) { *iReturnedIndex = i; return 1; } } return 0; }
// Are there still scripts that will be run in the current command?
int MorePendingScripts() {
int iItemIndex, iRCIndex;
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView); iItemIndex++) { iRCIndex = GetRCIndexFromRCItem(iItemIndex); if (g_RCData[iRCIndex].valid) { if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) return 1; } }
return 0; }
// Returns the number of scripts we think have started
int NumberRunningClients() {
int iItemIndex, iRCIndex; int nNumberRunning = 0;
for (iRCIndex = 0; iRCIndex < MAX_ROBOCLIENTS; iRCIndex += 1) { if (g_RCData[iRCIndex].valid) { if (g_RCData[iRCIndex].state == STATE_RUNNING) nNumberRunning++; } }
return nNumberRunning; }
// Cancel all scripts currently pending
int CancelPendingScripts(HWND hwnd) { int iItemIndex, iRCIndex; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView); iItemIndex++) { iRCIndex = GetRCIndexFromRCItem(iItemIndex); if (g_RCData[iRCIndex].valid) { if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) { g_RCData[iRCIndex].state = STATE_CONNECTED; LoadString(NULL, IDS_CANCELCOMMAND, psDisplayString, MAX_DISPLAY_STRING_LENGTH); ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, psDisplayString); } } }
MyKillTimer(hwnd, g_nIDTimer);
return 0; }
// Sets the timer using the Win32 SetTimer, and sets the appropriate menu items
// to disabled/enabled.
UINT_PTR MySetTimer(HWND hwnd, UINT_PTR nTimer, UINT nTimeout) {
// when we are setting the timer, we're disabling a bunch of things: menu
// items and edit boxes
EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKER, MF_GRAYED); EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKERFAST, MF_GRAYED); // EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_ADMINISTRATIVEWORKER,
// MF_GRAYED);
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_DATA, MF_GRAYED); EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_STW, MF_GRAYED); EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_BLANK, MF_GRAYED); EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_CONFIGURATIONSCRIPT, MF_GRAYED); // EnableMenuItem(g_hPopupMenu, ID__UPDATE, MF_GRAYED);
EnableMenuItem(g_hPopupMenu, ID__REBOOT, MF_GRAYED);
EnableWindow(GetDlgItem(hwnd, IDC_TERMSRVEDIT), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_DELAYEDIT), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_CLIENTSPERSET), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_SETDELAY), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_CANARYCHECK), FALSE); // and we're enabling "Cancel Pending tasks"
EnableMenuItem(g_hPopupMenu, ID_CANCEL, MF_ENABLED);
// We are also making sure that the number of clients per set, if 0,
// is set to MAX_ROBOCLIENTS
if (NumClientsPerSet(hwnd) == 0) { HWND hClientsPerSet; TCHAR sClientsPerSetText[MAX_NUMBERTEXT]; hClientsPerSet = GetDlgItem(hwnd, IDC_CLIENTSPERSET); _sntprintf(sClientsPerSetText, MAX_NUMBERTEXT, _T("%d"), MAX_ROBOCLIENTS); sClientsPerSetText[MAX_NUMBERTEXT - 1] = 0; SetWindowText(hClientsPerSet, sClientsPerSetText); } return SetTimer(hwnd, nTimer, nTimeout, 0); }
// Kills the timer and sets appropriate menu items disabled or enabled
int MyKillTimer(HWND hwnd, UINT_PTR nTimer) { // When killing the timer, re-enable menu items and edit boxes
EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKER, MF_ENABLED); EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKERFAST, MF_ENABLED); // EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_ADMINISTRATIVEWORKER,
// MF_ENABLED);
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_DATA, MF_ENABLED); EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_STW, MF_ENABLED); EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_BLANK, MF_ENABLED); EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_CONFIGURATIONSCRIPT, MF_ENABLED); // EnableMenuItem(g_hPopupMenu, ID__UPDATE, MF_ENABLED);
EnableMenuItem(g_hPopupMenu, ID__REBOOT, MF_ENABLED);
EnableWindow(GetDlgItem(hwnd, IDC_TERMSRVEDIT), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_DELAYEDIT), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_CLIENTSPERSET), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_SETDELAY), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_CANARYCHECK), TRUE); // and disable "Cancel Pending Tasks"
EnableMenuItem(g_hPopupMenu, ID_CANCEL, MF_GRAYED); return KillTimer(hwnd, nTimer); }
// Retrieves the delay in the IDC_DELAYEDIT box (turned into milliseconds)
int GetDelay(HWND hwnd) { HWND hDelayEdit; int nTimeout; TCHAR psDelayText[MAX_DELAYTEXT]; hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT); _ASSERTE(IsWindow(hDelayEdit)); GetWindowText(hDelayEdit, psDelayText, MAX_DELAYTEXT); nTimeout = _ttoi(psDelayText); nTimeout *= 1000;
if (nTimeout == 0) nTimeout = 100; // Don't allow a delay of 0
return nTimeout; }
// Retrieves the number in the IDC_CLIENTSPERSET box
int NumClientsPerSet(HWND hwnd) { HWND hClientsPerSet; TCHAR psClientsPerSet[MAX_DELAYTEXT];
hClientsPerSet = GetDlgItem(hwnd, IDC_CLIENTSPERSET); GetWindowText(hClientsPerSet, psClientsPerSet, MAX_DELAYTEXT);
return _ttoi(psClientsPerSet); }
// Retrieves the delay in the IDC_SETDELAY box, turned into milliseconds
int GetSetDelay(HWND hwnd) { HWND hSetDelayEdit; int nTimeout; TCHAR psDelayText[MAX_DELAYTEXT]; hSetDelayEdit = GetDlgItem(hwnd, IDC_SETDELAY); _ASSERTE(IsWindow(hSetDelayEdit)); GetWindowText(hSetDelayEdit, psDelayText, MAX_DELAYTEXT); nTimeout = _ttoi(psDelayText); nTimeout *= 60000; // minutes to ms
if (nTimeout == 0) nTimeout = GetDelay(hwnd); // Normal timer
return nTimeout; }
// Takes the command line string as an argument and modifies global variables
// for the arguments.
// Pops up a messagebox on error
int GetCommandLineArgs(TCHAR *psCommandLine) { TCHAR *psCurrPtr = psCommandLine; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH]; TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
if (*psCurrPtr == '\"') { psCurrPtr++; // skip the opening quote
// Handle if the first arg is quoted
while ((*psCurrPtr != 0) && (*psCurrPtr != '\"')) psCurrPtr++;
// then skip the " character
if (*psCurrPtr == '\"') psCurrPtr++; } else { // go forward in the array until you get a ' ' or until NULL
while((*psCurrPtr != 0) && (*psCurrPtr != ' ')) psCurrPtr++; }
// skip spaces
while(*psCurrPtr == ' ') psCurrPtr++;
// if the character is NULL, return 0 (no args)
if (*psCurrPtr == 0) return 0;
while (*psCurrPtr != 0) {
// now, check whether the next three are "-s:" and then non-null,
if (_tcsncmp(psCurrPtr, _T("-s:"), 3) == 0) { if ((psCurrPtr[3] == 0) || (psCurrPtr[3] == ' ')) { goto SHOWMSGBOX; } else { TCHAR *psStartOfName = &psCurrPtr[3]; int namelen = 0; while ((psStartOfName[namelen] != 0) && (psStartOfName[namelen] != ' ')) namelen++; _tcsncpy(g_TermSrvrName, psStartOfName, namelen); g_TermSrvrName[namelen] = 0; psCurrPtr = &psStartOfName[namelen]; } } else if (_tcsncmp(psCurrPtr, _T("-n:"), 3) == 0) { if ((psCurrPtr[3] == 0) || (psCurrPtr[3] == ' ')) { goto SHOWMSGBOX; } else { TCHAR *psStartOfNum = &psCurrPtr[3]; int numlen = 0;
while ((psStartOfNum[numlen] != 0) && (psStartOfNum[numlen] != ' ')) numlen++; g_nNumConnections = _ttoi(psStartOfNum); // CHANGE BACK FROM 64 TO 5
if ((g_nNumConnections < 1) || (g_nNumConnections > 64)) { g_nNumConnections = 3; goto SHOWMSGBOX; } psCurrPtr = &psStartOfNum[numlen]; } } else { // error
goto SHOWMSGBOX; }
// skip whitespace
while(*psCurrPtr == ' ') psCurrPtr++; } return 0; SHOWMSGBOX: LoadString(NULL, IDS_COMMANDLINESYNTAX, psDisplayString, MAX_DISPLAY_STRING_LENGTH); LoadString(NULL, IDS_COMMANDLINESYNTAXTITLE, psDisplayTitleString, MAX_DISPLAY_STRING_LENGTH); MessageBox(0, psDisplayString, psDisplayTitleString, 0); return -1; }
// log information to our global log file
int LogToLogFile(char *psLogData) { FILE *fp; SYSTEMTIME logloctime; TCHAR psTimeDatePart[TIMEBUFSIZE]; TCHAR psTimeTimePart[TIMEBUFSIZE]; char psTimeDatePartA[TIMEBUFSIZE]; char psTimeTimePartA[TIMEBUFSIZE];
// Get the time
GetLocalTime(&logloctime); // Get strings
GetDateFormat(0, 0, &logloctime, 0, psTimeDatePart, TIMEBUFSIZE); GetTimeFormat(0, 0, &logloctime, 0, psTimeTimePart, TIMEBUFSIZE);
// Make sure we are in ANSI
#ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, psTimeDatePart, -1, psTimeDatePartA, TIMEBUFSIZE, 0, 0); WideCharToMultiByte(CP_ACP, 0, psTimeTimePart, -1, psTimeTimePartA, TIMEBUFSIZE, 0, 0); #else
strncpy(psTimeDatePartA, psTimeDatePart, TIMEBUFSIZE); strncpy(psTimeTimePartA, psTimeTimePart, TIMEBUFSIZE); #endif
EnterCriticalSection(&g_LogFileCritSect);
// open the file
fp = fopen("log.txt", "a+t"); // write the information to the file
if (fp != 0) { // First, a timestamp
fprintf(fp, "%s %s\n", psTimeDatePartA, psTimeTimePartA); // Now, the message
fprintf(fp, "%s\n\n", psLogData); // close the file
fclose(fp); } else { // error
}
LeaveCriticalSection(&g_LogFileCritSect);
return 0; }
int ToAnsi(char *psDest, const TCHAR *psSrc, int nSizeOfBuffer) { #ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, psSrc, -1, psDest, nSizeOfBuffer, 0, 0); #else
_strncpy(psDest, psSrc, nSizeOfBuffer); #endif
return 0; }
// On close, clean up by disabling the listener socket then closing all open
// connections. This ensures the roboclients will know the roboserver has
// exited
int CleanUp(HWND hwnd) { int iItemIndex; int iRCIndex; TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH]; TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
// Disable listener
LoadString(NULL, IDS_CLOSINGLISTENER, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, psDisplayString); if (closesocket(g_listenersocket) != 0) { LoadString(NULL, IDS_COULDNOTCLOSELISTENER, psDisplayString, MAX_DISPLAY_STRING_LENGTH); LoadString(NULL, IDS_COULDNOTCLOSELISTENER, psDisplayString, MAX_DISPLAY_STRING_LENGTH); MessageBox(hwnd, psDisplayString, psDisplayTitleString, 0); }
// Set status line to "disconnecting clients..."
LoadString(NULL, IDS_DISCONNECTINGCLIENTS, psDisplayString, MAX_DISPLAY_STRING_LENGTH); SetWindowText(g_hErrorText, psDisplayString);
// Disconnect all the clients
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView); iItemIndex++) { iRCIndex = GetRCIndexFromRCItem(iItemIndex); if (g_RCData[iRCIndex].valid) { if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) { shutdown(g_RCData[iRCIndex].sock, SD_BOTH); closesocket(g_RCData[iRCIndex].sock); } } }
return 0; }
// This procedure is for the subclassing of all the tabbable controls so that
// I can tab between them.
LRESULT CALLBACK TabProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
int i; // Find the id of the hwnd
for (i = 0; i < NUM_TABBED_ITEMS; i++) { if (g_hwnd[i] == hwnd) break; }
switch (Msg) { case WM_KEYDOWN: if (wParam == VK_TAB) { int newItem = (i + (GetKeyState(VK_SHIFT) < 0 ? NUM_TABBED_ITEMS - 1 : 1)) % NUM_TABBED_ITEMS; // set the focus to the next or previous item
SetFocus(g_hwnd[newItem]); // if the control is before an edit box control, select all the
// text in the edit control that gets selected
if ((newItem > 2) && (newItem < 7)) SendMessage(g_hwnd[newItem], EM_SETSEL, 0, -1); } break; case WM_SETFOCUS: break; } return CallWindowProc((WNDPROC) g_OldProc[i], hwnd, Msg, wParam, lParam); }
// Message box on fatal error.
// IN: current hInstance of string resources
// ID in StringTable of string to display
void FatalErrMsgBox(HINSTANCE hInstance, UINT nMsgId) { TCHAR szTitleString[MAX_DISPLAY_STRING_LENGTH]; TCHAR szErrorString[MAX_DISPLAY_STRING_LENGTH];
LoadString(hInstance, IDS_FATALERROR, szTitleString, MAX_DISPLAY_STRING_LENGTH); LoadString(hInstance, nMsgId, szErrorString, MAX_DISPLAY_STRING_LENGTH);
MessageBox(0, szErrorString, szTitleString, 0); }
|