2015-11-25 23:22:31 +00:00
|
|
|
/* IPXWrapper test tools
|
|
|
|
* Copyright (C) 2015 Daniel Collins <solemnwarning@solemnwarning.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
|
|
* the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program; if not, write to the Free Software Foundation, Inc., 51
|
|
|
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define INITGUID
|
|
|
|
|
|
|
|
#include <dplay.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
DEFINE_GUID(TEST_APP_GUID, 0x38bef9eb, 0x6ad3, 0x4fc9, 0x97, 0xff, 0xfc, 0x3c, 0x7a, 0x55, 0x3b, 0x29);
|
|
|
|
|
|
|
|
static HANDLE exit_event = NULL;
|
|
|
|
|
|
|
|
#define assert_dp_call(name, expr) \
|
|
|
|
{ \
|
|
|
|
HRESULT err = (expr); \
|
|
|
|
if(err != DP_OK) \
|
|
|
|
{ \
|
|
|
|
fprintf(stderr, \
|
|
|
|
__FILE__ ":%u: " name ": %u\n", \
|
|
|
|
(unsigned int)(__LINE__), \
|
|
|
|
(unsigned int)(err)); \
|
|
|
|
exit(1); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lock_printf(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
static CRITICAL_SECTION cs;
|
|
|
|
static bool cs_init = false;
|
|
|
|
|
|
|
|
if(!cs_init)
|
|
|
|
{
|
|
|
|
InitializeCriticalSection(&cs);
|
|
|
|
cs_init = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
EnterCriticalSection(&cs);
|
|
|
|
|
|
|
|
va_list argv;
|
|
|
|
va_start(argv, fmt);
|
|
|
|
vprintf(fmt, argv);
|
|
|
|
va_end(argv);
|
|
|
|
|
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL FAR PASCAL copy_ipx_conn(
|
|
|
|
LPCGUID *lpguidSP,
|
|
|
|
LPVOID lpConnection,
|
|
|
|
DWORD dwConnectionSize,
|
|
|
|
LPCDPNAME lpName,
|
|
|
|
DWORD dwFlags,
|
|
|
|
LPVOID lpContext)
|
|
|
|
{
|
|
|
|
if(memcmp(lpguidSP, &DPSPGUID_IPX, sizeof(DPSPGUID_IPX)) == 0)
|
|
|
|
{
|
|
|
|
assert(*(void**)(lpContext) = malloc(dwConnectionSize));
|
|
|
|
memcpy(*(void**)(lpContext), lpConnection, dwConnectionSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL FAR PASCAL list_sessions_cb(
|
|
|
|
LPCDPSESSIONDESC2 lpThisSD,
|
|
|
|
LPDWORD lpdwTimeout,
|
|
|
|
DWORD dwFlags,
|
|
|
|
LPVOID lpContext)
|
|
|
|
{
|
|
|
|
if(lpThisSD)
|
|
|
|
{
|
|
|
|
unsigned char *uuid_str;
|
|
|
|
assert(UuidToString((UUID*)&(lpThisSD->guidInstance), &uuid_str) == RPC_S_OK);
|
|
|
|
|
|
|
|
lock_printf("session %s %s\n", uuid_str, lpThisSD->lpszSessionNameA);
|
|
|
|
|
|
|
|
RpcStringFree(&uuid_str);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/* Last session detected in this pass, return FALSE to make the
|
2017-09-19 23:30:14 +01:00
|
|
|
* invoking IDirectPlayX_EnumSessions call return rather than
|
2015-11-25 23:22:31 +00:00
|
|
|
* searching forever.
|
|
|
|
*/
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL FAR PASCAL list_players_cb(
|
|
|
|
DPID dpId,
|
|
|
|
DWORD dwPlayerType,
|
|
|
|
LPCDPNAME lpName,
|
|
|
|
DWORD dwFlags,
|
|
|
|
LPVOID lpContext)
|
|
|
|
{
|
|
|
|
lock_printf("player %u %s\n", (unsigned int)(dpId), lpName->lpszLongName);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD WINAPI recv_thread_main(LPVOID lpParameter)
|
|
|
|
{
|
|
|
|
IDirectPlay4 *dp = (IDirectPlay4*)(lpParameter);
|
|
|
|
|
|
|
|
DWORD bufsize = 0;
|
|
|
|
char *buf = NULL;
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
DPID player_from, player_to;
|
|
|
|
|
|
|
|
HRESULT err = IDirectPlayX_Receive(dp, &player_from, &player_to, 0, buf, &bufsize);
|
|
|
|
|
|
|
|
if(WaitForSingleObject(exit_event, 0) == WAIT_OBJECT_0)
|
|
|
|
{
|
|
|
|
/* We are exiting */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(err == DPERR_BUFFERTOOSMALL)
|
|
|
|
{
|
|
|
|
assert(buf = realloc(buf, bufsize));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if(err == DPERR_NOMESSAGES)
|
|
|
|
{
|
|
|
|
/* non-blocking I/O... ugh */
|
|
|
|
Sleep(50);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if(err != DP_OK)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "IDirectPlay4::Receive: %u\n", (unsigned int)(err));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(player_from != DPID_SYSMSG)
|
|
|
|
{
|
|
|
|
lock_printf("message %u %u %s\n",
|
|
|
|
(unsigned int)(player_from),
|
|
|
|
(unsigned int)(player_to),
|
|
|
|
buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
setbuf(stdout, NULL);
|
|
|
|
setbuf(stderr, NULL);
|
|
|
|
|
|
|
|
exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
assert(exit_event);
|
|
|
|
|
|
|
|
{
|
|
|
|
HRESULT err = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
|
|
if(err != S_OK)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "CoInitializeEx: %u\n", (unsigned int)(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IDirectPlay4 *dp;
|
|
|
|
assert_dp_call("CoCreateInstance",
|
|
|
|
CoCreateInstance(
|
|
|
|
&CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectPlay4A, (void**)(&dp)));
|
|
|
|
|
|
|
|
{
|
|
|
|
void *conn = NULL;
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::EnumConnections",
|
|
|
|
IDirectPlayX_EnumConnections(
|
|
|
|
dp, NULL, (LPDPENUMCONNECTIONSCALLBACK)(©_ipx_conn), &conn, 0));
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::InitializeConnection",
|
|
|
|
IDirectPlayX_InitializeConnection(dp, conn, 0));
|
|
|
|
|
|
|
|
free(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE recv_thread = CreateThread(NULL, 0, &recv_thread_main, dp, 0, NULL);
|
|
|
|
assert(recv_thread);
|
|
|
|
|
|
|
|
char line[1024];
|
|
|
|
while(lock_printf("ready\n"), fgets(line, sizeof(line), stdin))
|
|
|
|
{
|
|
|
|
char *cmd = strtok(line, " \n");
|
|
|
|
|
|
|
|
if(strcmp(cmd, "create_session") == 0)
|
|
|
|
{
|
|
|
|
char *session_name = strtok(NULL, " \n");
|
|
|
|
|
|
|
|
DPSESSIONDESC2 session;
|
|
|
|
memset(&session, 0, sizeof(session));
|
|
|
|
|
|
|
|
session.dwSize = sizeof(session);
|
|
|
|
session.guidApplication = TEST_APP_GUID;
|
|
|
|
session.lpszSessionNameA = session_name;
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::Open",
|
|
|
|
IDirectPlayX_Open(dp, &session, DPOPEN_CREATE));
|
|
|
|
|
|
|
|
DWORD bufsize = 0;
|
|
|
|
|
|
|
|
/* Need to call GetSessionDesc() to get the session
|
|
|
|
* GUID as Open() doesn't fill it in.
|
|
|
|
*/
|
|
|
|
|
|
|
|
assert(IDirectPlayX_GetSessionDesc(dp, NULL, &bufsize) == DPERR_BUFFERTOOSMALL);
|
|
|
|
|
|
|
|
DPSESSIONDESC2 *sd = malloc(bufsize);
|
|
|
|
assert(sd);
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::GetSessionDesc",
|
|
|
|
IDirectPlayX_GetSessionDesc(dp, sd, &bufsize));
|
|
|
|
|
|
|
|
unsigned char *uuid_str;
|
|
|
|
assert(UuidToString((UUID*)&(sd->guidInstance), &uuid_str) == RPC_S_OK);
|
|
|
|
|
|
|
|
lock_printf("session_guid %s\n", uuid_str);
|
|
|
|
|
|
|
|
RpcStringFree(&uuid_str);
|
|
|
|
|
|
|
|
free(sd);
|
|
|
|
}
|
|
|
|
else if(strcmp(cmd, "list_sessions") == 0)
|
|
|
|
{
|
|
|
|
DPSESSIONDESC2 session;
|
|
|
|
memset(&session, 0, sizeof(session));
|
|
|
|
|
|
|
|
session.dwSize = sizeof(session);
|
|
|
|
session.guidApplication = TEST_APP_GUID;
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::EnumSessions",
|
|
|
|
IDirectPlayX_EnumSessions(dp, &session, 3000, &list_sessions_cb, NULL, 0));
|
|
|
|
}
|
|
|
|
else if(strcmp(cmd, "join_session") == 0)
|
|
|
|
{
|
|
|
|
char *session_guid = strtok(NULL, " \n");
|
|
|
|
|
|
|
|
DPSESSIONDESC2 session;
|
|
|
|
memset(&session, 0, sizeof(session));
|
|
|
|
|
|
|
|
session.dwSize = sizeof(session);
|
|
|
|
UuidFromString((RPC_CSTR)(session_guid), &(session.guidInstance));
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::Open",
|
|
|
|
IDirectPlayX_Open(dp, &session, DPOPEN_JOIN));
|
|
|
|
}
|
|
|
|
else if(strcmp(cmd, "create_player") == 0)
|
|
|
|
{
|
|
|
|
DPID player_id;
|
|
|
|
|
|
|
|
DPNAME name;
|
|
|
|
memset(&name, 0, sizeof(name));
|
|
|
|
|
|
|
|
name.dwSize = sizeof(name);
|
|
|
|
name.lpszLongNameA = strtok(NULL, " \n");
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::CreatePlayer",
|
|
|
|
IDirectPlayX_CreatePlayer(dp, &player_id, &name, NULL, NULL, 0, 0));
|
|
|
|
|
|
|
|
lock_printf("player_id %u\n", (unsigned int)(player_id));
|
|
|
|
}
|
|
|
|
else if(strcmp(cmd, "list_players") == 0)
|
|
|
|
{
|
|
|
|
IDirectPlayX_EnumPlayers(dp, NULL, &list_players_cb, NULL, DPENUMPLAYERS_ALL);
|
|
|
|
}
|
|
|
|
else if(strcmp(cmd, "send_message") == 0)
|
|
|
|
{
|
|
|
|
DPID player_from = strtoul(strtok(NULL, " \n"), NULL, 10);
|
|
|
|
DPID player_to = strtoul(strtok(NULL, " \n"), NULL, 10);
|
|
|
|
char *message = strtok(NULL, " \n");
|
|
|
|
|
|
|
|
assert_dp_call("IDirectPlay4::Send",
|
|
|
|
IDirectPlayX_Send(dp, player_from, player_to, 0, message, strlen(message) + 1));
|
|
|
|
}
|
|
|
|
else if(strcmp(cmd, "exit") == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetEvent(exit_event);
|
|
|
|
WaitForSingleObject(recv_thread, INFINITE);
|
|
|
|
|
|
|
|
CloseHandle(recv_thread);
|
|
|
|
CloseHandle(exit_event);
|
|
|
|
|
|
|
|
IDirectPlayX_Release(dp);
|
|
|
|
|
|
|
|
CoUninitialize();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|