You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
6.5 KiB
213 lines
6.5 KiB
/*
|
|
* 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <process.h>
|
|
|
|
#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"<return> 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;
|
|
|
|
}
|