402 lines
11 KiB
C++
402 lines
11 KiB
C++
|
#define DBG 1
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <memory.h>
|
||
|
#include <malloc.h>
|
||
|
#include <stdlib.h>
|
||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#endif
|
||
|
#include <windows.h>
|
||
|
#include <rpc.h>
|
||
|
#include <midles.h>
|
||
|
#include "smgr.h"
|
||
|
|
||
|
#define RPC_CHAR WCHAR
|
||
|
|
||
|
#define CHECK_STATUS(status, string) if (status) { \
|
||
|
printf("%s failed - %d (%08x)\n", (string), (status), (status)); \
|
||
|
exit(1); \
|
||
|
} else printf("%s okay\n", (string));
|
||
|
|
||
|
PVOID SystemHeap = NULL;
|
||
|
|
||
|
extern "C" {
|
||
|
|
||
|
void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t bytes)
|
||
|
{
|
||
|
return RtlAllocateHeap(SystemHeap, 0, bytes);
|
||
|
}
|
||
|
|
||
|
void __RPC_USER MIDL_user_free(void __RPC_FAR * p)
|
||
|
{
|
||
|
RtlFreeHeap(SystemHeap, 0, p);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
inline UString *AllocateUString(unsigned short *pString)
|
||
|
{
|
||
|
int nStringSize = wcslen(pString); // we don't do + 1, because the UString data structure
|
||
|
// has one slot
|
||
|
UString *pNewString;
|
||
|
|
||
|
pNewString = (UString *)RtlAllocateHeap(SystemHeap, 0, sizeof(UString) + nStringSize * 2);
|
||
|
if (pNewString)
|
||
|
{
|
||
|
pNewString->nlength = nStringSize + 1;
|
||
|
wcscpy(&(pNewString->pString[0]), pString);
|
||
|
}
|
||
|
return pNewString;
|
||
|
}
|
||
|
|
||
|
inline UString *DuplicateUString(UString *pString)
|
||
|
{
|
||
|
if (pString)
|
||
|
{
|
||
|
// -1 because we have on slot in the structure
|
||
|
int nMemSize = sizeof(UString) + (pString->nlength - 1) * 2;
|
||
|
UString *pNewString;
|
||
|
|
||
|
pNewString = (UString *)RtlAllocateHeap(SystemHeap, 0, nMemSize);
|
||
|
memcpy(pNewString, pString, nMemSize);
|
||
|
return pNewString;
|
||
|
}
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
typedef enum tagSyncManagerState
|
||
|
{
|
||
|
smsRunning,
|
||
|
smsDone,
|
||
|
smsWaiting
|
||
|
} SyncManagerState;
|
||
|
|
||
|
FILE *fp;
|
||
|
FILE *fpLogFile;
|
||
|
long AvailableClients = 0;
|
||
|
long NeededClients = 0;
|
||
|
long RunningClients = 0;
|
||
|
BOOL fServerAvailable = FALSE;
|
||
|
SyncManagerCommands CurrentClientCommand = smcExec;
|
||
|
SyncManagerCommands CurrentServerCommand = smcExec;
|
||
|
UString *CurrentClientParam = NULL;
|
||
|
UString *CurrentServerParam = NULL;
|
||
|
SyncManagerState state = smsDone;
|
||
|
CRITICAL_SECTION ActionLock;
|
||
|
HANDLE GoEvent;
|
||
|
|
||
|
int __cdecl main(int argc, char *argv[])
|
||
|
{
|
||
|
RPC_STATUS status;
|
||
|
RPC_CHAR *string_binding;
|
||
|
RPC_BINDING_VECTOR *pBindingVector;
|
||
|
RPC_CHAR *Endpoint;
|
||
|
|
||
|
SystemHeap = GetProcessHeap();
|
||
|
|
||
|
if (argc != 2)
|
||
|
{
|
||
|
printf("Usage:\n\tsyncmgr script_file\n");
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
fp = fopen(argv[1], "rt");
|
||
|
if (fp == NULL)
|
||
|
{
|
||
|
printf("Couldn't open file: %s\n", argv[1]);
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
fpLogFile = fopen("c:\\syncmgr.log", "wt");
|
||
|
if (fpLogFile == NULL)
|
||
|
{
|
||
|
printf("Couldn't open log file: %s\n", "c:\\syncmgr.log");
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
InitializeCriticalSection(&ActionLock);
|
||
|
|
||
|
GoEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
|
|
||
|
status = RpcServerUseProtseqW(L"ncacn_ip_tcp", 300, 0);
|
||
|
CHECK_STATUS(status, "RpcServerUseProtseqW");
|
||
|
|
||
|
status = RpcServerInqBindings(&pBindingVector);
|
||
|
CHECK_STATUS(status, "RpcServerInqBindings");
|
||
|
|
||
|
status = RpcEpRegister(_SyncManager_v1_0_s_ifspec,
|
||
|
pBindingVector,
|
||
|
0,
|
||
|
0);
|
||
|
CHECK_STATUS(status, "RpcEpRegister");
|
||
|
|
||
|
status = RpcBindingToStringBindingW(pBindingVector->BindingH[0],
|
||
|
&string_binding);
|
||
|
CHECK_STATUS(status, "RpcBindingToStringBinding");
|
||
|
|
||
|
status = RpcStringBindingParseW(string_binding,
|
||
|
0, 0, 0, &Endpoint, 0);
|
||
|
|
||
|
CHECK_STATUS(status, "RpcStringBindingParse");
|
||
|
printf("Listening to %S:[%S]\n\n", "ncacn_ip_tcp", Endpoint);
|
||
|
|
||
|
status = RpcServerRegisterIf(_SyncManager_v1_0_s_ifspec,0,0);
|
||
|
CHECK_STATUS(status, "RpcServerRegisterIf");
|
||
|
|
||
|
printf("Server listening\n\n");
|
||
|
|
||
|
status = RpcServerListen(3, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
|
||
|
CHECK_STATUS(status, "RpcServerListen");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
inline BOOL IsWhiteSpace(int c)
|
||
|
{
|
||
|
return ((c == '\n')
|
||
|
|| (c == '\t')
|
||
|
|| (c == ' '));
|
||
|
}
|
||
|
|
||
|
void _GetCommand(handle_t IDL_handle, int ClientOrServer, SyncManagerCommands __RPC_FAR *cmd,
|
||
|
UString __RPC_FAR *__RPC_FAR *param)
|
||
|
{
|
||
|
RPC_CHAR NewCommand[400];
|
||
|
RPC_CHAR *pPosition;
|
||
|
RPC_CHAR *Clients;
|
||
|
RPC_CHAR *ClientCmd;
|
||
|
RPC_CHAR *SvrCmd;
|
||
|
RPC_CHAR *Ignored;
|
||
|
handle_t hClientHandle;
|
||
|
RPC_STATUS RpcStatus;
|
||
|
RPC_CHAR *StringBinding;
|
||
|
DWORD WaitResult;
|
||
|
|
||
|
RpcStatus = RpcBindingServerFromClient(IDL_handle, &hClientHandle);
|
||
|
if (RpcStatus != RPC_S_OK)
|
||
|
{
|
||
|
printf("RpcBindingServerFromClient failed: %d\n", RpcStatus);
|
||
|
*cmd = smcExit;
|
||
|
*param = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
RpcStatus = RpcBindingToStringBindingW(hClientHandle, &StringBinding);
|
||
|
if (RpcStatus != RPC_S_OK)
|
||
|
{
|
||
|
printf("RpcBindingToStringBindingW failed: %d\n", RpcStatus);
|
||
|
RpcBindingFree(&hClientHandle);
|
||
|
*cmd = smcExit;
|
||
|
*param = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
RpcBindingFree(&hClientHandle);
|
||
|
|
||
|
// if we came in the middle of a test, wait for it to finish
|
||
|
while (TRUE)
|
||
|
{
|
||
|
EnterCriticalSection(&ActionLock);
|
||
|
if (state != smsRunning)
|
||
|
break;
|
||
|
else
|
||
|
{
|
||
|
LeaveCriticalSection(&ActionLock);
|
||
|
printf("%S came in the middle of a test - waiting for it to finish\n", StringBinding);
|
||
|
Sleep(60000);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// are we the first one after a run?
|
||
|
if (state == smsDone)
|
||
|
{
|
||
|
printf("Client %S is reading next command\n", StringBinding);
|
||
|
ResetEvent(GoEvent);
|
||
|
RunningClients = 0;
|
||
|
|
||
|
// free old arguments if any
|
||
|
if (CurrentClientParam)
|
||
|
{
|
||
|
MIDL_user_free(CurrentClientParam);
|
||
|
CurrentClientParam = NULL;
|
||
|
}
|
||
|
if (CurrentServerParam)
|
||
|
{
|
||
|
MIDL_user_free(CurrentServerParam);
|
||
|
CurrentServerParam = NULL;
|
||
|
}
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
// get the new command line
|
||
|
pPosition = fgetws(NewCommand, sizeof(NewCommand), fp);
|
||
|
if (pPosition == NULL)
|
||
|
{
|
||
|
CurrentClientCommand = smcExit;
|
||
|
CurrentServerCommand = smcExit;
|
||
|
CurrentClientParam = NULL;
|
||
|
CurrentServerParam = NULL;
|
||
|
fprintf(fpLogFile, "End of file encountered\n");
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// parse the command
|
||
|
// first, trim spaces from the end
|
||
|
pPosition = wcschr(NewCommand, '\0') - 1;
|
||
|
while (IsWhiteSpace(*pPosition) && (pPosition > NewCommand))
|
||
|
{
|
||
|
*pPosition = 0;
|
||
|
pPosition --;
|
||
|
}
|
||
|
|
||
|
// was anything left?
|
||
|
if (pPosition == NewCommand)
|
||
|
continue;
|
||
|
|
||
|
// is this a comment line?
|
||
|
if (NewCommand[0] == ';')
|
||
|
continue;
|
||
|
|
||
|
// real line - should have the format #,srv_cmd,clnt_cmd
|
||
|
pPosition = wcschr(NewCommand, ',');
|
||
|
*pPosition = '\0';
|
||
|
Clients = NewCommand;
|
||
|
|
||
|
pPosition ++;
|
||
|
SvrCmd = pPosition;
|
||
|
pPosition = wcschr(pPosition, ',');
|
||
|
*pPosition = '\0';
|
||
|
|
||
|
ClientCmd = pPosition + 1;
|
||
|
|
||
|
NeededClients = wcstol(Clients, &Ignored, 10);
|
||
|
|
||
|
CurrentServerParam = AllocateUString(SvrCmd);
|
||
|
CurrentClientParam = AllocateUString(ClientCmd);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
state = smsWaiting;
|
||
|
}
|
||
|
|
||
|
if (CurrentClientCommand == smcExit)
|
||
|
{
|
||
|
printf("Client %S is getting exit command\n", StringBinding);
|
||
|
if (ClientOrServer)
|
||
|
{
|
||
|
*cmd = CurrentClientCommand;
|
||
|
*param = DuplicateUString(CurrentClientParam);
|
||
|
LeaveCriticalSection(&ActionLock);
|
||
|
goto CleanupAndExit;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*cmd = CurrentServerCommand;
|
||
|
*param = DuplicateUString(CurrentServerParam);
|
||
|
LeaveCriticalSection(&ActionLock);
|
||
|
goto CleanupAndExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ClientOrServer)
|
||
|
{
|
||
|
AvailableClients ++;
|
||
|
printf("Client %S has increased the number of available clients to %d (%d needed)\n",
|
||
|
StringBinding, AvailableClients, NeededClients);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fServerAvailable = TRUE;
|
||
|
printf("Server %S has become available\n", StringBinding);
|
||
|
}
|
||
|
|
||
|
// we have everybody for this test - kick it off
|
||
|
if ((AvailableClients >= NeededClients) && fServerAvailable)
|
||
|
{
|
||
|
printf("Client %S is kicking off tests\n", StringBinding);
|
||
|
*cmd = smcExec;
|
||
|
if (ClientOrServer)
|
||
|
{
|
||
|
AvailableClients --;
|
||
|
RunningClients = 1;
|
||
|
*param = DuplicateUString(CurrentClientParam);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fServerAvailable = FALSE;
|
||
|
*param = DuplicateUString(CurrentServerParam);
|
||
|
}
|
||
|
state = smsRunning;
|
||
|
LeaveCriticalSection(&ActionLock);
|
||
|
SetEvent(GoEvent);
|
||
|
|
||
|
// if we were client, create artificial delay for server to start
|
||
|
if (ClientOrServer)
|
||
|
Sleep(40000);
|
||
|
|
||
|
printf("Client %S kicked off test and returns\n", StringBinding);
|
||
|
goto CleanupAndExit;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// we don't have enough clients or the server is not there yet
|
||
|
LeaveCriticalSection(&ActionLock);
|
||
|
printf("Client %S starts waiting .... Tid is 0x%x\n", StringBinding, GetCurrentThreadId());
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
WaitResult = WaitForSingleObject(GoEvent, 600000);
|
||
|
if (WaitResult == WAIT_TIMEOUT)
|
||
|
{
|
||
|
printf("Client %S is still waiting for GoEvent ...\n", StringBinding);
|
||
|
}
|
||
|
}
|
||
|
while (WaitResult != WAIT_OBJECT_0);
|
||
|
|
||
|
EnterCriticalSection(&ActionLock);
|
||
|
|
||
|
if (ClientOrServer)
|
||
|
AvailableClients --;
|
||
|
else
|
||
|
fServerAvailable = FALSE;
|
||
|
|
||
|
if ((AvailableClients == 0) && (fServerAvailable == FALSE))
|
||
|
state = smsDone;
|
||
|
|
||
|
// if we are client and were left out don't do anything
|
||
|
if (ClientOrServer && ((RunningClients + 1) > NeededClients))
|
||
|
{
|
||
|
printf("Client %S was left out and returns. Available: %d\n", StringBinding, AvailableClients);
|
||
|
*param = NULL;
|
||
|
*cmd = smcNOP;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Client %S picked a command and returns\n", StringBinding);
|
||
|
if (ClientOrServer)
|
||
|
RunningClients ++;
|
||
|
*cmd = smcExec;
|
||
|
if (ClientOrServer)
|
||
|
*param = DuplicateUString(CurrentClientParam);
|
||
|
else
|
||
|
*param = DuplicateUString(CurrentServerParam);
|
||
|
}
|
||
|
LeaveCriticalSection(&ActionLock);
|
||
|
|
||
|
// if we were a client, create a 15 second artificial delay, giving the
|
||
|
// server a chance to start - this saves us some more sync-ing
|
||
|
if ((*cmd == smcExec) && ClientOrServer)
|
||
|
Sleep(15000);
|
||
|
|
||
|
CleanupAndExit:
|
||
|
RpcStringFreeW(&StringBinding);
|
||
|
}
|
||
|
|