/* * Filename: Main.cpp * Description: * Author: chrisdar 07.17.02 * * Tests support for CancelIPChangeNotify to cancel notififcations from TCP/IP. * Also exercises notification calls in multiple worker threads (pool size * controlled by NUM_THREAD). * * Each thread invokes an API method at random (selecting among the notification * APIs in wlbsctrl.dll). At no time should the call fail due to the state of * notifications in the dll. Thus multiple threads of control can use the * notification API without fear of stomping on one another. */ #include #include #include #include #include #include "wlbsctrl.h" #include "winsock2.h" /* The number of worker threads to create */ #define NUM_THREAD 8 /* The number of random numbers to generate */ #define NUM_RAND 100 /* Mnemonic for the 4 API methods */ #define CONN_UP 0 #define CONN_DOWN 1 #define CONN_RESET 2 #define CONN_CANCEL 3 /* Function pointers for notification APIs */ NLBNotificationConnectionUp pfnConnectionUp = NULL; NLBNotificationConnectionDown pfnConnectionDown = NULL; NLBNotificationConnectionReset pfnConnectionReset = NULL; NLBNotificationCancelNotify pfnCancelNotify = NULL; /* Set true when main thread wants worker threads to complete */ BOOL g_fexit = FALSE; /* Array of handles to the worker threads */ HANDLE g_hThread[NUM_THREAD]; /* Couldn't get rand() to generate unique random numbers in worker threads. Resorted to generating an array of random numbers and cycling through it */ UINT uiRand[NUM_RAND]; /* Index of next random number to use. Shared by worker threads, so this is proctected by a critical section */ UINT uiIndex = 0; /* Protects uiIndex */ CRITICAL_SECTION cs; /* Only way I could get the thread id to each worker thread. Used only in dumped output so I know which thread is doing the work */ UINT tid[NUM_THREAD]; /* The function executed by the worker threads */ unsigned __stdcall rndm_notify(void* p) { DWORD dwStatus; DWORD dwNLBStatus = 0; /* Get my thread id */ DWORD dwtid = *((DWORD*) p); while (!g_fexit) { Sleep(2000); EnterCriticalSection(&cs); UINT uiMethod = uiRand[uiIndex]; uiIndex = (uiIndex++)%NUM_RAND; LeaveCriticalSection(&cs); switch(uiMethod) { case CONN_UP: dwStatus = (*pfnConnectionUp)(inet_addr("10.0.0.110"), htons(500), inet_addr("10.0.0.204"), htons(500), 50, &dwNLBStatus); break; case CONN_DOWN: dwStatus = (*pfnConnectionDown)(inet_addr("10.0.0.110"), htons(500), inet_addr("10.0.0.204"), htons(500), 50, &dwNLBStatus); break; case CONN_RESET: dwStatus = (*pfnConnectionReset)(inet_addr("10.0.0.110"), htons(500), inet_addr("10.0.0.204"), htons(500), 50, &dwNLBStatus); break; case CONN_CANCEL: dwStatus = (*pfnCancelNotify)(); break; default: continue; } if (dwStatus != ERROR_SUCCESS) { wprintf(L"Thread %4d: notification %u failed with %d\n", dwtid, uiMethod, dwStatus); } else { wprintf(L"Thread %4d: notification %u succeeded\n", dwtid, uiMethod); } } dwStatus = (*pfnCancelNotify)(); if (dwStatus == ERROR_SUCCESS) { wprintf(L"Thread %4d: tcp/ip notifications canceled without error\n"); } else { wprintf(L"Thread %4d: canceling tcp/ip notifications failed with error %d\n", dwStatus); } wprintf(L"Thread %4d: exiting\n", dwtid); return 0; } int __cdecl wmain (int argc, WCHAR ** argv) { HINSTANCE hDLL = NULL; int iRet = 0; int i = 0; DWORD dwStatus = 0; ZeroMemory(g_hThread, sizeof(g_hThread)); InitializeCriticalSection(&cs); srand( (unsigned)time( NULL ) ); for (i = 0; i < NUM_RAND; i++) { uiRand[i] = rand()*4/RAND_MAX; } hDLL = LoadLibrary(L"wlbsctrl.dll"); if (!hDLL) { dwStatus = GetLastError(); wprintf(L"Unable to open wlbsctrl.dll... GetLastError() returned %u\n", dwStatus); iRet = -1; goto exit; } pfnConnectionUp = (NLBNotificationConnectionUp)GetProcAddress(hDLL, "WlbsConnectionUp"); pfnConnectionDown = (NLBNotificationConnectionDown)GetProcAddress(hDLL, "WlbsConnectionDown"); pfnConnectionReset = (NLBNotificationConnectionReset)GetProcAddress(hDLL, "WlbsConnectionReset"); pfnCancelNotify = (NLBNotificationCancelNotify)GetProcAddress(hDLL, "WlbsCancelConnectionNotify"); if (!pfnConnectionUp || !pfnConnectionDown || !pfnConnectionReset || !pfnCancelNotify) { dwStatus = GetLastError(); wprintf(L"Unable to get procedure address... GetLastError() returned %u\n", dwStatus); iRet = -2; goto exit; } wprintf(L"Creating %u threads\n", NUM_THREAD); for (i=0; i < NUM_THREAD; i++) { g_hThread[i] = (HANDLE) _beginthreadex( NULL, 0, rndm_notify, &tid[i], 0, &tid[i] ); if (g_hThread[i] == 0) { wprintf(L"thread creation failed with error %d\n", errno); iRet = -4; goto exit; } Sleep(100); } wprintf(L" to end threads and cancel\n"); (void)getchar(); g_fexit = TRUE; dwStatus = WaitForMultipleObjects(NUM_THREAD, g_hThread, TRUE, INFINITE); DWORD dwStatus2 = (*pfnCancelNotify)(); if (dwStatus2 == ERROR_SUCCESS) { wprintf(L"tcp/ip notifications canceled without error\n"); } else { wprintf(L"canceling tcp/ip notifications failed with error %d\n", dwStatus2); } if (dwStatus != WAIT_OBJECT_0 + NUM_THREAD - 1) { wprintf(L"wait on threads failed with error %d\n", dwStatus); iRet = -5; goto exit; } exit: if (hDLL != NULL) FreeLibrary(hDLL); DeleteCriticalSection(&cs); return iRet; }