]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - net_master.c
E4M9 was added to the Transfusion map list
[xonotic/darkplaces.git] / net_master.c
index 8fd7ed8c46bd6e5c4f6915802bf0cfdc8559df35..2b8444c224e955c47e52f7f35300c322f6ad8658 100644 (file)
@@ -19,17 +19,60 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 // net_master.c
 
-#include <malloc.h>
 #include "quakedef.h"
 
+
+cvar_t sv_public = {0, "sv_public", "0"};
+cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "180"};
+
 cvar_t sv_masters [] =
 {
        {CVAR_SAVE, "sv_master1", ""},
        {CVAR_SAVE, "sv_master2", ""},
        {CVAR_SAVE, "sv_master3", ""},
-       {CVAR_SAVE, "sv_master4", ""}
+       {CVAR_SAVE, "sv_master4", ""},
+       {0, "sv_masterextra1", "rick.cube-sol.net"},
+       {0, "sv_masterextra2", "198.88.152.4"},
+       {0, "sv_masterextra3", "68.102.242.12"}
 };
 
+static double nextheartbeattime = 0;
+
+
+/*
+====================
+Master_AllowHeartbeat
+
+Allow (or not) NET_Heartbeat to proceed depending on various factors
+====================
+*/
+qboolean Master_AllowHeartbeat (int priority)
+{
+       // LordHavoc: make advertising optional
+       if (!sv_public.integer)
+               return false;
+       // LordHavoc: don't advertise singleplayer games
+       if (svs.maxclients < 2)
+               return false;
+       // if it's a state change (client connected), limit next heartbeat to no
+       // more than 30 sec in the future
+       if (priority == 1 && nextheartbeattime > realtime + 30.0)
+               nextheartbeattime = realtime + 30.0;
+       if (priority <= 1 && realtime < nextheartbeattime)
+               return false;
+       // limit heartbeatperiod to 30 to 270 second range,
+       // lower limit is to avoid abusing master servers with excess traffic,
+       // upper limit is to avoid timing out on the master server (which uses
+       // 300 sec timeout)
+       if (sv_heartbeatperiod.value < 30)
+               Cvar_SetValueQuick(&sv_heartbeatperiod, 30);
+       if (sv_heartbeatperiod.value > 270)
+               Cvar_SetValueQuick(&sv_heartbeatperiod, 270);
+       // send a heartbeat as often as the admin wants
+       nextheartbeattime = realtime + sv_heartbeatperiod.value;
+       return true;
+}
+
 
 /*
 ====================
@@ -38,27 +81,31 @@ Master_BuildGetServers
 Build a getservers request for a master server
 ====================
 */
-char* Master_BuildGetServers (void)
+const char* Master_BuildGetServers (void)
 {
        static int nextmaster = 0;
        cvar_t* sv_master;
        char request [256];
-       
-       if (nextmaster >= sizeof (sv_masters) / sizeof (sv_masters[0]))
+
+       if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
        {
                nextmaster = 0;
                return NULL;
        }
 
-       sv_master = &sv_masters[nextmaster++];
-
-       // No master, no heartbeat
-       if (sv_master->string[0] == '\0')
+       // find a non-empty master server address in the list
+       for(;;)
        {
-               nextmaster = 0;
-               return NULL;
+               sv_master = &sv_masters[nextmaster++];
+               if (sv_master->string[0])
+                       break;
+               if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
+               {
+                       nextmaster = 0;
+                       return NULL;
+               }
        }
-       
+
        // Build the heartbeat
        snprintf (request, sizeof (request), "getservers %s %u empty full\x0A", gamename, NET_PROTOCOL_VERSION);
        SZ_Clear (&net_message);
@@ -78,26 +125,30 @@ Master_BuildHeartbeat
 Build an heartbeat for a master server
 ====================
 */
-char* Master_BuildHeartbeat (void)
+const char* Master_BuildHeartbeat (void)
 {
        static int nextmaster = 0;
        cvar_t* sv_master;
-       
-       if (nextmaster >= sizeof (sv_masters) / sizeof (sv_masters[0]))
+
+       if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
        {
                nextmaster = 0;
                return NULL;
        }
 
-       sv_master = &sv_masters[nextmaster++];
-
-       // No master, no heartbeat
-       if (sv_master->string[0] == '\0')
+       // find a non-empty master server address in the list
+       for(;;)
        {
-               nextmaster = 0;
-               return NULL;
+               sv_master = &sv_masters[nextmaster++];
+               if (sv_master->string[0])
+                       break;
+               if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
+               {
+                       nextmaster = 0;
+                       return NULL;
+               }
        }
-       
+
        // Build the heartbeat
        SZ_Clear (&net_message);
        MSG_WriteLong (&net_message, -1);
@@ -169,6 +220,8 @@ Initialize the code that handles master server requests and reponses
 void Master_Init (void)
 {
        unsigned int ind;
+       Cvar_RegisterVariable (&sv_public);
+       Cvar_RegisterVariable (&sv_heartbeatperiod);
        for (ind = 0; ind < sizeof (sv_masters) / sizeof (sv_masters[0]); ind++)
                Cvar_RegisterVariable (&sv_masters[ind]);
 }
@@ -185,11 +238,18 @@ void Master_ParseServerList (net_landriver_t* dfunc)
 {
        int control;
        qbyte* servers;
-       int ipaddr;
+       qbyte* crtserver;
+       unsigned int ipaddr;
        struct qsockaddr svaddr;
        char ipstring [32];
 
-       if (net_message.cursize < sizeof(int))
+       if (developer.integer)
+       {
+               Con_Printf("Master_ParseServerList: packet received:\n");
+               SZ_HexDumpToConsole(&net_message);
+       }
+
+       if (net_message.cursize < (int)sizeof(int))
                return;
 
        // is the cache full?
@@ -202,28 +262,28 @@ void Master_ParseServerList (net_landriver_t* dfunc)
        if (control != -1)
                return;
 
-       if (strncmp (net_message.data + 4, "getserversResponse\\", 19)) 
+       if (strncmp (net_message.data + 4, "getserversResponse\\", 19))
                return;
 
-       // Skip the next 18 bytes
+       // Skip the next 19 bytes
        MSG_ReadLong(); MSG_ReadLong(); MSG_ReadLong(); MSG_ReadLong();
        MSG_ReadShort(); MSG_ReadByte();
 
-       servers = alloca (net_message.cursize - 23);
+       crtserver = servers = Z_Malloc (net_message.cursize - 23);
        memcpy (servers , net_message.data + 23, net_message.cursize - 23);
 
        // Extract the IP addresses
-       while ((ipaddr = (servers[3] << 24) + (servers[2] << 16) + (servers[1] << 8) + servers[0]) != -1)
+       while ((ipaddr = (crtserver[3] << 24) | (crtserver[2] << 16) | (crtserver[1] << 8) | crtserver[0]) != 0xFFFFFFFF)
        {
-               int port = (servers[5] << 8) + servers[4];
+               int port = (crtserver[5] << 8) | crtserver[4];
 
-               if (port == -1 || port == 0)
+               if (port < 1 || port >= 65535)
                        break;
 
                port = ((port >> 8) & 0xFF) + ((port & 0xFF) << 8);
                sprintf (ipstring, "%u.%u.%u.%u:%hu",
                                        ipaddr & 0xFF, (ipaddr >> 8) & 0xFF,
-                                       (ipaddr >> 16) & 0xFF, ipaddr >> 24,
+                                       (ipaddr >> 16) & 0xFF, (ipaddr >> 24) & 0xFF,
                                        port);
                dfunc->GetAddrFromName (ipstring, &svaddr);
 
@@ -238,8 +298,10 @@ void Master_ParseServerList (net_landriver_t* dfunc)
                dfunc->Write(dfunc->controlSock, net_message.data, net_message.cursize, &svaddr);
                SZ_Clear(&net_message);
 
-               if (servers[6] != '\\')
+               if (crtserver[6] != '\\')
                        break;
-               servers += 7;
+               crtserver += 7;
        }
+
+       Z_Free (servers);
 }