1
0
mirror of https://github.com/solemnwarning/directplay-lite synced 2024-12-30 16:45:37 +01:00

Initial implementation of soak test client side.

This commit is contained in:
Daniel Collins 2018-10-28 15:47:47 +00:00
parent 988ea0c3b6
commit 685a6c27cf
3 changed files with 333 additions and 0 deletions

View File

@ -28,6 +28,7 @@ SET CPP_OBJS=^
tests/PacketDeserialiser.obj^
tests/PacketSerialiser.obj^
tests/SendQueue.obj^
tests/soak-peer-client.obj^
tests/soak-peer-server.obj
REM .obj files to be compiled from .c source files
@ -143,6 +144,12 @@ echo ==
link /debug /out:tests/all-tests.exe %TEST_OBJS% %TEST_LIBS% || exit /b
echo:
echo ==
echo == link /debug /out:tests/soak-peer-client.exe tests/soak-peer-client.obj dxguid.lib ole32.lib
echo ==
link /debug /out:tests/soak-peer-client.exe tests/soak-peer-client.obj dxguid.lib ole32.lib || exit /b
echo:
echo ==
echo == link /debug /out:tests/soak-peer-server.exe tests/soak-peer-server.obj dxguid.lib ole32.lib
echo ==

302
tests/soak-peer-client.cpp Normal file
View File

@ -0,0 +1,302 @@
#include <winsock2.h>
#include <algorithm>
#include <dplay8.h>
#include <mutex>
#include <objbase.h>
#include <psapi.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <windows.h>
/* Durations specified in milliseconds. */
#define TEST_DURATION (60 * 60 * 1000)
#define MEMORY_STATS_INTERVAL (60 * 1000)
static const GUID APP_GUID = { 0x8723c2c6, 0x0b89, 0x4ea0, { 0xad, 0xe8, 0xec, 0x53, 0x66, 0x51, 0x68, 0x9f } };
static int64_t pc_freq;
static int64_t now_ms();
static int64_t start_time;
static int64_t usage_time;
static IDirectPlay8Peer *instance;
static bool disconnected;
static HRESULT CALLBACK callback(PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage);
static void print_usage();
static void timed_printf(const char *fmt, ...);
int main(int argc, char **argv)
{
{
LARGE_INTEGER li;
QueryPerformanceFrequency(&li);
pc_freq = li.QuadPart;
}
HRESULT res = CoInitialize(NULL);
if(res != S_OK)
{
fprintf(stderr, "CoInitialize failed with HRESULT %08x\n", (unsigned)(res));
return 1;
}
/* Interval between destroying and re-creating the DirectPlay8Peer
* object and closing and re-initialising it.
*
* Each of these will increase as the test runs.
*/
int64_t reconstruct_interval = (120 * 1000);
int64_t reinitialise_interval = (30 * 1000);
start_time = now_ms();
int64_t end_time = start_time + TEST_DURATION;
print_usage();
while(now_ms() < end_time)
{
timed_printf("Constructing DirectPlay8Peer instance...");
res = CoCreateInstance(CLSID_DirectPlay8Peer, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Peer, (void**)(&instance));
if(res != S_OK)
{
fprintf(stderr, "Failed to construct DirectPlay8Peer instance (HRESULT %08x)\n", (unsigned)(res));
return 1;
}
print_usage();
int64_t construct_time = now_ms();
int64_t destruct_time = construct_time + reconstruct_interval;
reconstruct_interval *= 2;
while(now_ms() < destruct_time && now_ms() < end_time)
{
timed_printf("Initialising DirectPlay8Peer instance...");
disconnected = false;
int64_t initialise_time = now_ms();
int64_t close_time = now_ms() + reinitialise_interval;
reinitialise_interval *= 2;
res = instance->Initialize(NULL, &callback, 0);
if(res != S_OK)
{
fprintf(stderr, "IDirectPlay8Peer::Initialize failed with HRESULT %08x\n", (unsigned)(res));
return 1;
}
print_usage();
bool connected = false;
while(!disconnected && now_ms() < close_time && now_ms() < destruct_time && now_ms() < end_time)
{
if(!connected)
{
timed_printf("Enumerating sessions...");
DPN_APPLICATION_DESC app_desc;
memset(&app_desc, 0, sizeof(app_desc));
app_desc.dwSize = sizeof(app_desc);
app_desc.guidApplication = APP_GUID;
IDirectPlay8Address *enum_address;
res = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (void**)(&enum_address));
if(res != S_OK)
{
fprintf(stderr, "Failed to construct DirectPlay8Address instance (HRESULT %08x)\n", (unsigned)(res));
return 1;
}
res = enum_address->SetSP(&CLSID_DP8SP_TCPIP);
if(res != S_OK)
{
fprintf(stderr, "IDirectPlay8Address::SetSP failed with HRESULT %08x\n", (unsigned)(res));
return 1;
}
IDirectPlay8Address *connect_address = NULL;
res = instance->EnumHosts(&app_desc, NULL, enum_address, NULL, 0, 0, 0, 0, &connect_address, NULL, DPNENUMHOSTS_SYNC);
if(res != S_OK)
{
fprintf(stderr, "IDirectPlay8Peer::EnumHosts failed with HRESULT %08x\n", (unsigned)(res));
return 1;
}
enum_address->Release();
if(connect_address == NULL)
{
continue;
}
timed_printf("Connecting to session...");
res = instance->Connect(
&app_desc, /* pdnAppDesc */
connect_address, /* pHostAddr */
NULL, /* pDeviceInfo */
NULL, /* pdnSecurity */
NULL, /* pdnCredentials */
NULL, /* pvUserConnectData */
0, /* dwUserConnectDataSize */
NULL, /* pvPlayerContext */
NULL, /* pvAsyncContext */
NULL, /* phAsyncHandle */
DPNCONNECT_SYNC); /* dwFlags */
if(res != S_OK)
{
fprintf(stderr, "IDirectPlay8Peer::Connect failed with HRESULT %08x\n", (unsigned)(res));
return 1;
}
connected = true;
connect_address->Release();
}
int64_t sleep_until = std::min({ usage_time, close_time, destruct_time, end_time });
int64_t sleep_for = sleep_until - now_ms();
if(sleep_for > 0)
{
Sleep(sleep_for);
}
if(now_ms() >= usage_time)
{
print_usage();
}
}
timed_printf("Closing DirectPlay8Peer instance...");
/* Alternate between hard/soft closes. */
static bool hard_close = false;
res = instance->Close(hard_close ? DPNCLOSE_IMMEDIATE : 0);
if(res != S_OK)
{
fprintf(stderr, "IDirectPlay8Peer::Close() failed with HRESULT %08x\n", (unsigned int)(res));
return 1;
}
hard_close = !hard_close;
print_usage();
}
timed_printf("Destroying DirectPlay8Peer instance...");
instance->Release();
instance = NULL;
print_usage();
}
CoUninitialize();
return 0;
}
static int64_t now_ms()
{
LARGE_INTEGER ticks;
QueryPerformanceCounter(&ticks);
return ticks.QuadPart / (pc_freq / 1000);
}
static HRESULT CALLBACK callback(PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage)
{
switch(dwMessageType)
{
case DPN_MSGID_ENUM_HOSTS_RESPONSE:
{
DPNMSG_ENUM_HOSTS_RESPONSE *ehr = (DPNMSG_ENUM_HOSTS_RESPONSE*)(pMessage);
IDirectPlay8Address **connect_address = (IDirectPlay8Address**)(ehr->pvUserContext);
ehr->pAddressSender->AddRef();
*connect_address = ehr->pAddressSender;
break;
}
case DPN_MSGID_TERMINATE_SESSION:
{
timed_printf("Lost connection to session");
disconnected = true;
break;
}
case DPN_MSGID_CREATE_PLAYER:
{
DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage);
timed_printf("New player ID: %u", (unsigned)(cp->dpnidPlayer));
break;
}
case DPN_MSGID_DESTROY_PLAYER:
{
DPNMSG_DESTROY_PLAYER *dp = (DPNMSG_DESTROY_PLAYER*)(pMessage);
timed_printf("Destroyed player ID: %u", (unsigned)(dp->dpnidPlayer));
break;
}
default:
{
break;
}
}
return S_OK;
}
static void print_usage()
{
static SIZE_T peak_usage = 0;
PROCESS_MEMORY_COUNTERS_EX mc;
mc.cb = sizeof(mc);
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)(&mc), sizeof(mc));
if(peak_usage < mc.PrivateUsage)
{
peak_usage = mc.PrivateUsage;
}
timed_printf("Current memory usage: %u bytes, peak usage: %u bytes",
(unsigned)(mc.PrivateUsage), (unsigned)(peak_usage));
usage_time = now_ms() + MEMORY_STATS_INTERVAL;
}
static void timed_printf(const char *fmt, ...)
{
static std::mutex lock;
std::unique_lock<std::mutex> l(lock);
int64_t now = now_ms();
printf("[T+%06u.%03us] ",
(unsigned)((now - start_time) / 1000),
(unsigned)((now - start_time) % 1000));
va_list argv;
va_start(argv, fmt);
vprintf(fmt, argv);
va_end(argv);
printf("\n");
}

View File

@ -181,6 +181,30 @@ static int64_t now_ms()
static HRESULT CALLBACK callback(PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage)
{
switch(dwMessageType)
{
case DPN_MSGID_CREATE_PLAYER:
{
DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage);
timed_printf("New player ID: %u", (unsigned)(cp->dpnidPlayer));
break;
}
case DPN_MSGID_DESTROY_PLAYER:
{
DPNMSG_DESTROY_PLAYER *dp = (DPNMSG_DESTROY_PLAYER*)(pMessage);
timed_printf("Destroyed player ID: %u", (unsigned)(dp->dpnidPlayer));
break;
}
default:
{
break;
}
}
return S_OK;
}