diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1549811c127ec64ffde85558bffdf92487223aaf..14f9c47906d39568789b29a0d949b41c1b3e70b0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -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 diff --git a/src/d_clisrv.h b/src/d_clisrv.h index f3eb524238d84461147b38252c107ed248dea578..d43432619e9dd4632d91067f764479ecce3ab780 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -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;