2020-09-30 17:17:25 +02:00

324 lines
6.5 KiB
C++

/*
*
* tlxbox.cpp
*
* VC-Xbox transport
*
*/
#include "precomp.h"
#include "tlutil.h"
HINSTANCE hInstance;
LPDBF lpdbf;
TLCALLBACKTYPE lpfnTlCallback;
#if DBG
DEBUG_VERSION ('T', 'L', "TCP/IP Transport for Xbox");
#else
RELEASE_VERSION ('T', 'L', "TCP/IP Transport for Xbox");
#endif
HPID g_hpid;
PDM_CONNECTION pdconMain;
PDM_CONNECTION pdconPoll;
BYTE *pbEMBuffer;
DWORD cbEMBuffer;
DWORD ibEMBuffer;
BYTE rgbReceiveBuffer[1024];
int ibReceiveBuffer;
BOOL WINAPI
DllMain(
HINSTANCE hInst,
ULONG uReason,
LPVOID lpReserved
)
{
switch (uReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls (hInst);
hInstance = hInst;
break;
case DLL_PROCESS_DETACH:
hInstance = NULL;
break;
}
return TRUE;
}
LPAVS
DBGVersionCheck(
)
{
return &Avs;
}
void FillPacket64(LPSTR sz, BYTE *pb, DWORD cb)
{
WORD w = 0;
int ibit = 0;
while(cb--) {
w |= *pb++ << ibit;
ibit += 8;
while(ibit >= 6) {
*sz++ = (w & 0x3f) + '!';
w >>= 6;
ibit -= 6;
}
}
if(ibit)
*sz++ = (w & 0x3f) + '!';
*sz = 0;
}
int GetPacket64(LPCSTR sz, BYTE *pb, DWORD cb)
{
DWORD ib = 0;
WORD w = 0;
int ibit = 0;
while(*sz) {
w |= (*sz++ - '!') << ibit;
ibit += 6;
while(ibit >= 8) {
if(++ib > cb)
return -1;
*pb++ = w & 0xff;
w >>= 8;
ibit -= 8;
}
}
assert(!w);
return ib;
}
XOSD XosdSendTlPacket(PDM_CONNECTION s, char ch, DWORD cb, PVOID pv, BOOL fReply)
{
HRESULT hr;
char sz[512];
DWORD cch = sizeof sz;
XOSD xosd;
BYTE *pbRet;
DWORD *pcbRet;
DWORD cbMax;
if(fReply) {
pbRet = pbEMBuffer;
pcbRet = &ibEMBuffer;
cbMax = cbEMBuffer;
} else {
pbRet = rgbReceiveBuffer;
pcbRet = (DWORD *)&ibReceiveBuffer;
cbMax = sizeof rgbReceiveBuffer;
}
sprintf(sz, "msvc!%c ", ch);
if(ch == '0') {
/* We're not actually sending a packet, we're going to send a
* command. We're doing it through here so we can get the xosd
* return */
hr = DmSendCommand(s, (LPCSTR)pv, sz, &cch);
} else if(pv) {
/* First we're going to send. We follow the logic that 256 bytes is
* the breakeven between encoded and binary */
if(cb > 256) {
int cbT;
sprintf(sz + 6, "g%d", cb);
hr = DmSendCommand(s, sz, NULL, 0);
if(FAILED(hr))
return xosdGeneral;
assert(hr == XBDM_READYFORBIN);
if(FAILED(DmSendBinary(s, pv, cb)))
return xosdGeneral;
hr = DmReceiveStatusResponse(s, sz, &cch);
} else {
FillPacket64(sz + 7, (LPBYTE)pv, cb);
hr = DmSendCommand(s, sz, sz, &cch);
}
} else
/* No packet; we're going to do a get */
hr = DmSendCommand(s, "msvc!g", sz, &cch);
if(FAILED(hr))
xosd = xosdGeneral;
else if(hr == XBDM_BINRESPONSE) {
/* We got a packet coming back */
BYTE *pb = (BYTE *)pcbRet;
DWORD cb = sizeof(DWORD);
int i;
/* First we read the data size, then we read the data */
for(i = 0; i < 2; ++i) {
if(FAILED(DmReceiveBinary(s, pb, cb, NULL)))
return xosdGeneral;
/* Got the data size, so set up for the data */
if(!i) {
pb = pbRet;
cb = *pcbRet;
assert(cb <= cbMax);
}
}
xosd = xosdNone;
} else {
int i;
/* We got back a valid response */
switch(sz[5]) {
case 'p':
/* We have a packet in the reply */
i = GetPacket64(sz + 6, pbRet, cbMax);
if(i < 0) {
assert(false);
*pcbRet = cbMax;
} else
*pcbRet = i;
xosd = xosdNone;
break;
case 'g':
/* The packet is there for the taking */
xosd = XosdSendTlPacket(s, 'g', cb, pv, fReply);
break;
case 'x':
/* No packet, but an xosd */
if(!sscanf(sz + 6, "%d", &i))
xosd = xosdUnknown;
else
xosd = i;
break;
}
}
return xosd;
}
DWORD Notify(LPCSTR sz)
{
if(sz[6] == 'g') {
if(!pdconPoll || XosdSendTlPacket(pdconPoll, 'g', 0, NULL, TRUE) !=
xosdNone)
/* Can't get the packet */
return 0;
} else {
ibReceiveBuffer = GetPacket64(sz + 7, rgbReceiveBuffer, sizeof
rgbReceiveBuffer);
assert(ibReceiveBuffer >= 0);
}
/* Do we care what kind of packet this is? */
lpfnTlCallback(g_hpid, ibReceiveBuffer, (LPARAM)rgbReceiveBuffer);
return 0;
}
XOSD WINAPI
TLFunc(
TLF wCommand,
HPID hpid,
WPARAM wParam,
LPARAM lParam
)
{
XOSD xosd = xosdNone;
char szHostName[256];
HRESULT hr;
WSADATA wsad;
switch(wCommand) {
case tlfInit:
lpdbf = (LPDBF)wParam;
lpfnTlCallback = (TLCALLBACKTYPE)lParam;
break;
case tlfDestroy:
break;
case tlfGetVersion:
memcpy((PVOID)lParam, &Avs, sizeof Avs);
break;
case tlfConnect:
if(hpid == NULL)
/* Just snooping around */
return xosdNone;
_asm int 3
assert(!pdconMain);
assert(g_hpid == NULL);
g_hpid = hpid;
/* Find the Xbox */
if(GetHostName(mptUnknown, szHostName, sizeof szHostName,
lpdbf->lpfnGetSet))
DmSetXboxName(szHostName);
/* Make sure we'll be able to receive notifications */
if(FAILED(DmNotify(DM_PERSISTENT, NULL)))
return xosdCannotConnect;
if(FAILED(DmRegisterNotificationProcessor("msvc", Notify)))
return xosdUnknown;
/* Connect two sockets -- one for requests, and one to get reply
* packets */
if(FAILED(DmOpenConnection(&pdconMain)))
return xosdCannotConnect;
if(FAILED(DmSendCommand(pdconMain, "kd disable", NULL, 0)) ||
FAILED(DmSendCommand(pdconMain, "msvc!c", NULL, 0)) ||
FAILED(DmOpenConnection(&pdconPoll)))
{
DmCloseConnection(pdconMain);
return xosdCannotConnect;
}
/* We're connected now */
break;
case tlfDisconnect:
DmNotify(0, NULL);
if(pdconMain) {
DmCloseConnection(pdconMain);
pdconMain = NULL;
}
if(pdconPoll) {
DmCloseConnection(pdconPoll);
pdconPoll = NULL;
}
g_hpid = NULL;
break;
case tlfLoadDM:
if(FAILED(DmSendCommand(pdconMain, "msvc!l", NULL, 0)))
xosd = xosdGeneral;
break;
case tlfSetBuffer:
pbEMBuffer = (LPBYTE)lParam;
cbEMBuffer = wParam;
break;
case tlfRequest:
xosd = XosdSendTlPacket(pdconMain, 'q', wParam, (LPVOID)lParam, TRUE);
break;
case tlfReply:
xosd = XosdSendTlPacket(pdconPoll, 'p', wParam, (LPVOID)lParam, FALSE);
break;
case tlfDebugPacket:
xosd = XosdSendTlPacket(pdconMain, 'd', wParam, (LPVOID)lParam, FALSE);
break;
default:
assert(FALSE);
xosd = xosdUnknown;
break;
}
return xosd;
}