Skip to content

Commit

Permalink
Added app version check between netplay host and clients to ensure in…
Browse files Browse the repository at this point in the history
…terface compatibility.
  • Loading branch information
thor2016 committed Mar 23, 2024
1 parent cc234ae commit cc61b7b
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 19 deletions.
82 changes: 72 additions & 10 deletions src/drivers/Qt/NetPlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ void NetPlayServer::onRomLoad()
//printf("New ROM Loaded!\n");
FCEU_WRAPPER_LOCK();

opsCrc32 = 0;
netPlayFrameData.reset();

inputClear();
inputFrameCount = static_cast<uint32_t>(currFrameCounter);

Expand All @@ -460,13 +463,16 @@ void NetPlayServer::onStateLoad()
//printf("New State Loaded!\n");
FCEU_WRAPPER_LOCK();

opsCrc32 = 0;
netPlayFrameData.reset();

inputClear();
inputFrameCount = static_cast<uint32_t>(currFrameCounter);

// New State has been loaded by server, signal clients to load and sync
for (auto& client : clientList )
{
//sendRomLoadReq( client );
sendRomLoadReq( client );
sendStateSyncReq( client );
}
FCEU_WRAPPER_UNLOCK();
Expand All @@ -477,12 +483,16 @@ void NetPlayServer::onNesReset()
//printf("NES Reset Event!\n");
FCEU_WRAPPER_LOCK();

opsCrc32 = 0;
netPlayFrameData.reset();

inputClear();
inputFrameCount = static_cast<uint32_t>(currFrameCounter);

// NES Reset has occurred on server, signal clients sync
for (auto& client : clientList )
{
sendRomLoadReq( client );
sendStateSyncReq( client );
}
FCEU_WRAPPER_UNLOCK();
Expand Down Expand Up @@ -530,7 +540,27 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
msg->toHostByteOrder();
printf("Authorize: Player: %i Passwd: %s\n", msg->playerId, msg->pswd);

if (sessionPasswd.isEmpty())
bool version_chk_ok = true;

if (enforceAppVersionCheck)
{
version_chk_ok = (msg->appVersionMajor == FCEU_VERSION_MAJOR) &&
(msg->appVersionMinor == FCEU_VERSION_MINOR) &&
(msg->appVersionPatch == FCEU_VERSION_PATCH);
}

if (!version_chk_ok)
{
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT);
errorMsg.setFlag(netPlayTextMsgFlags::ERROR);
errorMsg.printf("Client/Host Version Mismatch:\nHost version is %i.%i.%i\nClient version is %i.%i.%i",
FCEU_VERSION_MAJOR, FCEU_VERSION_MINOR, FCEU_VERSION_PATCH,
msg->appVersionMajor, msg->appVersionMinor, msg->appVersionPatch);
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
client->flushData();
}
else if (sessionPasswd.isEmpty())
{
authentication_passed = true;
}
Expand All @@ -542,6 +572,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
{
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT);
errorMsg.setFlag(netPlayTextMsgFlags::ERROR);
errorMsg.printf("Invalid Password");
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
client->flushData();
Expand All @@ -564,6 +595,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
{
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT);
errorMsg.setFlag(netPlayTextMsgFlags::ERROR);
errorMsg.printf("Player %i role is not available", msg->playerId+1);
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
client->flushData();
Expand Down Expand Up @@ -693,6 +725,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
else
{
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
errorMsg.setFlag(netPlayTextMsgFlags::WARNING);
errorMsg.printf("Host is rejected ROMs load request");
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
}
Expand Down Expand Up @@ -726,14 +759,10 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s

FCEU_WRAPPER_LOCK();
serverRequestedStateLoad = true;
// Clients will be resync'd during this load call.
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
serverRequestedStateLoad = false;
FCEU_WRAPPER_UNLOCK();

opsCrc32 = 0;
netPlayFrameData.reset();
inputClear();
resyncAllClients();
}
}
break;
Expand Down Expand Up @@ -1347,11 +1376,28 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )

switch (msgId)
{
case NETPLAY_INFO_MSG:
{
auto *msg = static_cast<netPlayTextMsg<256>*>(msgBuf);
msg->toHostByteOrder();
FCEU_printf("NetPlay Info: %s\n", msg->getBuffer());

if (msg->isFlagSet(netPlayTextMsgFlags::DISCONNECT))
{
sock->disconnectFromHost();
}
FCEU_DispMessage("NetPlay Errors... check message log",0);
}
break;
case NETPLAY_ERROR_MSG:
{
auto *msg = static_cast<netPlayTextMsg<256>*>(msgBuf);
msg->toHostByteOrder();
FCEU_printf("NetPlay Error: 0x%X %s\n", msg->code, msg->getBuffer());
FCEU_printf("NetPlay Error: %s\n", msg->getBuffer());

QString msgBoxTxt = tr("Host has replied with an error:\n\n");
msgBoxTxt += tr(msg->getBuffer());
QMessageBox::critical( consoleWindow, tr("NetPlay Error"), msgBoxTxt, QMessageBox::Ok );

if (msg->isFlagSet(netPlayTextMsgFlags::DISCONNECT))
{
Expand Down Expand Up @@ -1547,21 +1593,28 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent)
grid->addWidget( lbl, 0, 0, 1, 1 );
grid->addWidget( frameLeadSpinBox, 0, 1, 1, 1 );

bool enforceAppVersionChk = false;
enforceAppVersionChkCBox = new QCheckBox(tr("Enforce Client Versions Match"));
grid->addWidget( enforceAppVersionChkCBox, 1, 0, 1, 2 );
g_config->getOption("SDL.NetPlayHostEnforceAppVersionChk", &enforceAppVersionChk);
enforceAppVersionChkCBox->setChecked(enforceAppVersionChk);

bool romLoadReqEna = false;
allowClientRomReqCBox = new QCheckBox(tr("Allow Client ROM Load Requests"));
grid->addWidget( allowClientRomReqCBox, 1, 0, 1, 2 );
grid->addWidget( allowClientRomReqCBox, 2, 0, 1, 2 );
g_config->getOption("SDL.NetPlayHostAllowClientRomLoadReq", &romLoadReqEna);
allowClientRomReqCBox->setChecked(romLoadReqEna);

bool stateLoadReqEna = false;
allowClientStateReqCBox = new QCheckBox(tr("Allow Client State Load Requests"));
grid->addWidget( allowClientStateReqCBox, 2, 0, 1, 2 );
grid->addWidget( allowClientStateReqCBox, 3, 0, 1, 2 );
g_config->getOption("SDL.NetPlayHostAllowClientStateLoadReq", &stateLoadReqEna);
allowClientStateReqCBox->setChecked(stateLoadReqEna);

connect(passwordRequiredCBox, SIGNAL(stateChanged(int)), this, SLOT(passwordRequiredChanged(int)));
connect(allowClientRomReqCBox, SIGNAL(stateChanged(int)), this, SLOT(allowClientRomReqChanged(int)));
connect(allowClientStateReqCBox, SIGNAL(stateChanged(int)), this, SLOT(allowClientStateReqChanged(int)));
connect(enforceAppVersionChkCBox, SIGNAL(stateChanged(int)), this, SLOT(enforceAppVersionChkChanged(int)));

startButton = new QPushButton( tr("Start") );
startButton->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton));
Expand Down Expand Up @@ -1609,11 +1662,19 @@ void NetPlayHostDialog::passwordRequiredChanged(int state)
void NetPlayHostDialog::allowClientRomReqChanged(int state)
{
g_config->setOption("SDL.NetPlayHostAllowClientRomLoadReq", state != Qt::Unchecked);
g_config->save();
}
//-----------------------------------------------------------------------------
void NetPlayHostDialog::allowClientStateReqChanged(int state)
{
g_config->setOption("SDL.NetPlayHostAllowClientStateLoadReq", state != Qt::Unchecked);
g_config->save();
}
//-----------------------------------------------------------------------------
void NetPlayHostDialog::enforceAppVersionChkChanged(int state)
{
g_config->setOption("SDL.NetPlayHostEnforceAppVersionChk", state != Qt::Unchecked);
g_config->save();
}
//-----------------------------------------------------------------------------
void NetPlayHostDialog::onStartClicked(void)
Expand All @@ -1632,6 +1693,7 @@ void NetPlayHostDialog::onStartClicked(void)
server->setRole( playerRoleBox->currentData().toInt() );
server->sessionName = sessionNameEntry->text();
server->setMaxLeadFrames( frameLeadSpinBox->value() );
server->setEnforceAppVersionCheck( enforceAppVersionChkCBox->isChecked() );
server->setAllowClientRomLoadRequest( allowClientRomReqCBox->isChecked() );
server->setAllowClientStateLoadRequest( allowClientStateReqCBox->isChecked() );

Expand Down
4 changes: 4 additions & 0 deletions src/drivers/Qt/NetPlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class NetPlayServer : public QTcpServer

uint32_t getMaxLeadFrames(){ return maxLeadFrames; }
void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; }
void setEnforceAppVersionCheck(bool value){ enforceAppVersionCheck = value; }
void setAllowClientRomLoadRequest(bool value){ allowClientRomLoadReq = value; }
void setAllowClientStateLoadRequest(bool value){ allowClientStateLoadReq = value; }

Expand All @@ -164,6 +165,7 @@ class NetPlayServer : public QTcpServer
uint32_t maxLeadFrames = 10u;
uint32_t clientWaitCounter = 0;
uint32_t inputFrameCount = 0;
bool enforceAppVersionCheck = true;
bool allowClientRomLoadReq = false;
bool allowClientStateLoadReq = false;

Expand Down Expand Up @@ -334,6 +336,7 @@ class NetPlayHostDialog : public QDialog
QLineEdit *passwordEntry;
QCheckBox *passwordRequiredCBox;
QSpinBox *frameLeadSpinBox;
QCheckBox *enforceAppVersionChkCBox;
QCheckBox *allowClientRomReqCBox;
QCheckBox *allowClientStateReqCBox;

Expand All @@ -345,6 +348,7 @@ public slots:
void passwordRequiredChanged(int state);
void allowClientRomReqChanged(int state);
void allowClientStateReqChanged(int state);
void enforceAppVersionChkChanged(int state);
};

class NetPlayJoinDialog : public QDialog
Expand Down
28 changes: 19 additions & 9 deletions src/drivers/Qt/NetPlayMsgDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <string.h>
#include <stdint.h>
#include "version.h"

// Network Byte Swap Functions
uint16_t netPlayByteSwap(uint16_t);
Expand Down Expand Up @@ -92,45 +93,56 @@ struct netPlayAuthResp
{
netPlayMsgHdr hdr;

uint16_t appVersionMajor;
uint16_t appVersionMinor;
uint32_t appVersionPatch;
char playerId;
char userName[64];
char pswd[72];

netPlayAuthResp(void)
: hdr(NETPLAY_AUTH_RESP, sizeof(netPlayAuthResp)), playerId(NETPLAY_SPECTATOR)
: hdr(NETPLAY_AUTH_RESP, sizeof(netPlayAuthResp)),
appVersionMajor(FCEU_VERSION_MAJOR), appVersionMinor(FCEU_VERSION_MINOR), appVersionPatch(FCEU_VERSION_PATCH),
playerId(NETPLAY_SPECTATOR)
{
memset(pswd, 0, sizeof(pswd));
}

void toHostByteOrder()
{
hdr.toHostByteOrder();
appVersionMajor = netPlayByteSwap(appVersionMajor);
appVersionMinor = netPlayByteSwap(appVersionMinor);
appVersionPatch = netPlayByteSwap(appVersionPatch);
}

void toNetworkByteOrder()
{
hdr.toNetworkByteOrder();
appVersionMajor = netPlayByteSwap(appVersionMajor);
appVersionMinor = netPlayByteSwap(appVersionMinor);
appVersionPatch = netPlayByteSwap(appVersionPatch);
}
};

struct netPlayTextMsgFlags
{
static const uint32_t DISCONNECT = 0x00000001;
static const uint32_t WARNING = 0x00000002;
static const uint32_t INFO = 0x00000004;
static const uint32_t ERROR = 0x00000002;
static const uint32_t WARNING = 0x00000004;
static const uint32_t INFO = 0x00000008;
};

template <size_t N=8>
struct netPlayTextMsg
{
netPlayMsgHdr hdr;

unsigned short code;
unsigned short flags;
unsigned short dataSize;
uint32_t flags;
uint16_t dataSize;

netPlayTextMsg(int type)
: hdr(type, sizeof(netPlayTextMsg)), code(0), flags(0), dataSize(0)
: hdr(type, sizeof(netPlayTextMsg)), flags(0), dataSize(0)
{
hdr.msgSize = sizeof(*this) - N + 1;
memset(data, 0, N);
Expand Down Expand Up @@ -202,15 +214,13 @@ struct netPlayTextMsg
void toHostByteOrder()
{
hdr.toHostByteOrder();
code = netPlayByteSwap(code);
flags = netPlayByteSwap(flags);
dataSize = netPlayByteSwap(dataSize);
}

void toNetworkByteOrder()
{
hdr.toNetworkByteOrder();
code = netPlayByteSwap(code);
flags = netPlayByteSwap(flags);
dataSize = netPlayByteSwap(dataSize);
}
Expand Down
1 change: 1 addition & 0 deletions src/drivers/Qt/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ InitConfig()
config->addOption("players", "SDL.NetworkPlayers", 1);
config->addOption("SDL.NetPlayHostAllowClientRomLoadReq", 0);
config->addOption("SDL.NetPlayHostAllowClientStateLoadReq", 0);
config->addOption("SDL.NetPlayHostEnforceAppVersionChk", 1);

// input configuration options
config->addOption("input1", "SDL.Input.0", "GamePad.0");
Expand Down

0 comments on commit cc61b7b

Please sign in to comment.