Merge branch 'working-server-incompatibility-checks' into 'next'

Actually tell you if the server is running an incompatible version

See merge request STJr/SRB2!1509
This commit is contained in:
Nev3r 2021-07-16 16:55:41 -04:00
commit 6d76d05d62
2 changed files with 209 additions and 78 deletions

View file

@ -1150,15 +1150,14 @@ static boolean CL_SendJoin(void)
CONS_Printf(M_GetText("Sending join request...\n"));
netbuffer->packettype = PT_CLIENTJOIN;
netbuffer->u.clientcfg.modversion = MODVERSION;
strncpy(netbuffer->u.clientcfg.application,
SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application);
if (splitscreen || botingame)
localplayers++;
netbuffer->u.clientcfg.localplayers = localplayers;
netbuffer->u.clientcfg._255 = 255;
netbuffer->u.clientcfg.packetversion = PACKETVERSION;
netbuffer->u.clientcfg.version = VERSION;
netbuffer->u.clientcfg.subversion = SUBVERSION;
strncpy(netbuffer->u.clientcfg.application, SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application);
CleanupPlayerName(consoleplayer, cv_playername.zstring);
if (splitscreen)
@ -1201,6 +1200,21 @@ static INT32 FindRejoinerNum(SINT8 node)
return -1;
}
static UINT8
GetRefuseReason (INT32 node)
{
if (!node || FindRejoinerNum(node) != -1)
return 0;
else if (bannednode && bannednode[node])
return REFUSE_BANNED;
else if (!cv_allownewplayer.value)
return REFUSE_JOINS_DISABLED;
else if (D_NumPlayers() >= cv_maxplayers.value)
return REFUSE_SLOTS_FULL;
else
return 0;
}
static void SV_SendServerInfo(INT32 node, tic_t servertime)
{
UINT8 *p;
@ -1219,14 +1233,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers();
netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value;
if (!node || FindRejoinerNum(node) != -1)
netbuffer->u.serverinfo.refusereason = 0;
else if (!cv_allownewplayer.value)
netbuffer->u.serverinfo.refusereason = 1;
else if (D_NumPlayers() >= cv_maxplayers.value)
netbuffer->u.serverinfo.refusereason = 2;
else
netbuffer->u.serverinfo.refusereason = 0;
netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
sizeof netbuffer->u.serverinfo.gametypename);
@ -1344,9 +1351,6 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->packettype = PT_SERVERCFG;
netbuffer->u.servercfg.version = VERSION;
netbuffer->u.servercfg.subversion = SUBVERSION;
netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer;
netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots);
netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic);
@ -1667,20 +1671,24 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
if (serverlistcount >= MAXSERVERLIST)
return; // list full
if (info->_255 != 255)
return;/* old packet format */
/* check it later if connecting to this one */
if (node != servernode)
{
if (info->_255 != 255)
return;/* old packet format */
if (info->packetversion != PACKETVERSION)
return;/* old new packet format */
if (info->packetversion != PACKETVERSION)
return;/* old new packet format */
if (info->version != VERSION)
return; // Not same version.
if (info->version != VERSION)
return; // Not same version.
if (info->subversion != SUBVERSION)
return; // Close, but no cigar.
if (info->subversion != SUBVERSION)
return; // Close, but no cigar.
if (strcmp(info->application, SRB2APPLICATION))
return;/* that's a different mod */
if (strcmp(info->application, SRB2APPLICATION))
return;/* that's a different mod */
}
i = serverlistcount++;
}
@ -1829,6 +1837,72 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
#endif // ifndef NONET
static const char * InvalidServerReason (INT32 i)
{
#define EOT "\nPress ESC\n"
serverinfo_pak *info = &serverlist[i].info;
/* magic number for new packet format */
if (info->_255 != 255)
{
return
"Outdated server (version unknown).\n" EOT;
}
if (strncmp(info->application, SRB2APPLICATION, sizeof
info->application))
{
return va(
"%s cannot connect\n"
"to %s servers.\n" EOT,
SRB2APPLICATION,
info->application);
}
if (
info->packetversion != PACKETVERSION ||
info->version != VERSION ||
info->subversion != SUBVERSION
){
return va(
"Incompatible %s versions.\n"
"(server version %d.%d.%d)\n" EOT,
SRB2APPLICATION,
info->version / 100,
info->version % 100,
info->subversion);
}
switch (info->refusereason)
{
case REFUSE_BANNED:
return
"You have been banned\n"
"from the server.\n" EOT;
case REFUSE_JOINS_DISABLED:
return
"The server is not accepting\n"
"joins for the moment.\n" EOT;
case REFUSE_SLOTS_FULL:
return va(
"Maximum players reached: %d\n" EOT,
info->maxplayer);
default:
if (info->refusereason)
{
return
"You can't join.\n"
"I don't know why,\n"
"but you can't join.\n" EOT;
}
}
return NULL;
#undef EOT
}
/** Called by CL_ServerConnectionTicker
*
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
@ -1859,23 +1933,23 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
return true;
}
// Quit here rather than downloading files and being refused later.
if (serverlist[i].info.refusereason)
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
if (serverlist[i].info.refusereason == 1)
M_StartMessage(M_GetText("The server is not accepting\njoins for the moment.\n\nPress ESC\n"), NULL, MM_NOTHING);
else if (serverlist[i].info.refusereason == 2)
M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
else
M_StartMessage(M_GetText("You can't join.\nI don't know why,\nbut you can't join.\n\nPress ESC\n"), NULL, MM_NOTHING);
return false;
}
if (client)
{
const char *reason = InvalidServerReason(i);
// Quit here rather than downloading files
// and being refused later.
if (reason)
{
char *message = Z_StrDup(reason);
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(message, NULL, MM_NOTHING);
Z_Free(message);
return false;
}
D_ParseFileneeded(serverlist[i].info.fileneedednum,
serverlist[i].info.fileneeded);
CONS_Printf(M_GetText("Checking files...\n"));
@ -3620,6 +3694,78 @@ static size_t TotalTextCmdPerTic(tic_t tic)
return total;
}
static const char *
ConnectionRefused (SINT8 node, INT32 rejoinernum)
{
clientconfig_pak *cc = &netbuffer->u.clientcfg;
boolean rejoining = (rejoinernum != -1);
if (!node)/* server connecting to itself */
return NULL;
if (
cc->modversion != MODVERSION ||
strncmp(cc->application, SRB2APPLICATION,
sizeof cc->application)
){
return/* this is probably client's fault */
"Incompatible.";
}
else if (bannednode && bannednode[node])
{
return
"You have been banned\n"
"from the server.";
}
else if (cc->localplayers != 1)
{
return
"Wrong player count.";
}
if (!rejoining)
{
if (!cv_allownewplayer.value)
{
return
"The server is not accepting\n"
"joins for the moment.";
}
else if (D_NumPlayers() >= cv_maxplayers.value)
{
return va(
"Maximum players reached: %d",
cv_maxplayers.value);
}
}
if (luafiletransfers)
{
return
"The serveris broadcasting a file\n"
"requested by a Lua script.\n"
"Please wait a bit and then\n"
"try rejoining.";
}
if (netgame)
{
const tic_t th = 2 * cv_joindelay.value * TICRATE;
if (joindelay > th)
{
return va(
"Too many people are connecting.\n"
"Please wait %d seconds and then\n"
"try rejoining.",
(joindelay - th) / TICRATE);
}
}
return NULL;
}
/** Called when a PT_CLIENTJOIN packet is received
*
* \param node The packet sender
@ -3630,33 +3776,14 @@ static void HandleConnect(SINT8 node)
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1];
INT32 rejoinernum;
INT32 i;
const char *refuse;
rejoinernum = FindRejoinerNum(node);
if (bannednode && bannednode[node])
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server."));
else if (netbuffer->u.clientcfg._255 != 255 ||
netbuffer->u.clientcfg.packetversion != PACKETVERSION)
SV_SendRefuse(node, "Incompatible packet formats.");
else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application))
SV_SendRefuse(node, "Different SRB2 modifications\nare not compatible.");
else if (netbuffer->u.clientcfg.version != VERSION
|| netbuffer->u.clientcfg.subversion != SUBVERSION)
SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION));
else if (!cv_allownewplayer.value && node && rejoinernum == -1)
SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment."));
else if (D_NumPlayers() >= cv_maxplayers.value && rejoinernum == -1)
SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value));
else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client?
SV_SendRefuse(node, M_GetText("Too many players from\nthis node."));
else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join?
SV_SendRefuse(node, M_GetText("No players from\nthis node."));
else if (luafiletransfers)
SV_SendRefuse(node, M_GetText("The server is broadcasting a file\nrequested by a Lua script.\nPlease wait a bit and then\ntry rejoining."));
else if (netgame && joindelay > 2 * (tic_t)cv_joindelay.value * TICRATE)
SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."),
(joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE));
refuse = ConnectionRefused(node, rejoinernum);
if (refuse)
SV_SendRefuse(node, refuse);
else
{
#ifndef NONET

View file

@ -22,11 +22,15 @@
#include "mserv.h"
/*
The 'packet version' is used to distinguish packet formats.
This version is independent of VERSION and SUBVERSION. Different
applications may follow different packet versions.
The 'packet version' is used to distinguish packet
formats. This version is independent of VERSION and
SUBVERSION. Different applications may follow different
packet versions.
If you change the struct or the meaning of a field
therein, increment this number.
*/
#define PACKETVERSION 3
#define PACKETVERSION 4
// Network play related stuff.
// There is a data struct that stores network
@ -141,9 +145,6 @@ typedef struct
typedef struct
{
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
// Server launch stuffs
UINT8 serverplayer;
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
@ -190,16 +191,19 @@ typedef struct
typedef struct
{
UINT8 _255;/* see serverinfo_pak */
UINT8 packetversion;
UINT8 modversion;
char application[MAXAPPLICATION];
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
UINT8 localplayers;
UINT8 mode;
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME];
} ATTRPACK clientconfig_pak;
enum {
REFUSE_JOINS_DISABLED = 1,
REFUSE_SLOTS_FULL,
REFUSE_BANNED,
};
#define MAXSERVERNAME 32
#define MAXFILENEEDED 915
// This packet is too large
@ -217,7 +221,7 @@ typedef struct
UINT8 subversion;
UINT8 numberofplayer;
UINT8 maxplayer;
UINT8 refusereason; // 0: joinable, 1: joins disabled, 2: full
UINT8 refusereason; // 0: joinable, REFUSE enum
char gametypename[24];
UINT8 modifiedgame;
UINT8 cheatsenabled;