2 Copyright (C) 2002 Mathieu Olivier
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 cvar_t sv_masters [] =
27 {CVAR_SAVE, "sv_master1", ""},
28 {CVAR_SAVE, "sv_master2", ""},
29 {CVAR_SAVE, "sv_master3", ""},
30 {CVAR_SAVE, "sv_master4", ""}
36 Master_BuildGetServers
38 Build a getservers request for a master server
41 char* Master_BuildGetServers (void)
43 static int nextmaster = 0;
47 if (nextmaster >= sizeof (sv_masters) / sizeof (sv_masters[0]))
53 sv_master = &sv_masters[nextmaster++];
55 // No master, no heartbeat
56 if (sv_master->string[0] == '\0')
62 // Build the heartbeat
63 snprintf (request, sizeof (request), "getservers %s %u empty full\x0A", gamename, NET_PROTOCOL_VERSION);
64 SZ_Clear (&net_message);
65 MSG_WriteLong (&net_message, -1);
66 MSG_WriteString (&net_message, request);
68 net_message.cursize--; // we don't send the trailing '\0'
70 return sv_master->string;
78 Build an heartbeat for a master server
81 char* Master_BuildHeartbeat (void)
83 static int nextmaster = 0;
86 if (nextmaster >= sizeof (sv_masters) / sizeof (sv_masters[0]))
92 sv_master = &sv_masters[nextmaster++];
94 // No master, no heartbeat
95 if (sv_master->string[0] == '\0')
101 // Build the heartbeat
102 SZ_Clear (&net_message);
103 MSG_WriteLong (&net_message, -1);
104 MSG_WriteString (&net_message, "heartbeat DarkPlaces\x0A");
106 net_message.cursize--; // we don't send the trailing '\0'
108 return sv_master->string;
116 Handle the master server messages
119 int Master_HandleMessage (void)
121 const char* string = MSG_ReadString ();
123 // If it's a "getinfo" request
124 if (!strncmp (string, "getinfo", 7))
129 length = snprintf (response, sizeof (response), "infoResponse\x0A"
130 "\\gamename\\%s\\modname\\%s\\sv_maxclients\\%d"
131 "\\clients\\%d\\mapname\\%s\\hostname\\%s\\protocol\\%d",
132 gamename, com_modname, svs.maxclients, net_activeconnections,
133 sv.name, hostname.string, NET_PROTOCOL_VERSION);
135 // Too long to fit into the buffer?
136 if (length >= sizeof (response))
139 // If there was a challenge in the getinfo message
140 if (string[7] == ' ')
142 string += 8; // skip the header and the space
144 // If the challenge wouldn't fit into the buffer
145 if (length + 11 + strlen (string) >= sizeof (response))
148 sprintf (response + length, "\\challenge\\%s", string);
151 SZ_Clear (&net_message);
152 MSG_WriteLong (&net_message, -1);
153 MSG_WriteString (&net_message, response);
155 return net_message.cursize - 1;
166 Initialize the code that handles master server requests and reponses
169 void Master_Init (void)
172 for (ind = 0; ind < sizeof (sv_masters) / sizeof (sv_masters[0]); ind++)
173 Cvar_RegisterVariable (&sv_masters[ind]);
179 Master_ParseServerList
181 Parse getserverResponse messages
184 void Master_ParseServerList (net_landriver_t* dfunc)
189 struct qsockaddr svaddr;
192 if (net_message.cursize < sizeof(int))
195 // is the cache full?
196 if (hostCacheCount == HOSTCACHESIZE)
200 control = BigLong(*((int *)net_message.data));
205 if (strncmp (net_message.data + 4, "getserversResponse\\", 19))
208 // Skip the next 18 bytes
209 MSG_ReadLong(); MSG_ReadLong(); MSG_ReadLong(); MSG_ReadLong();
210 MSG_ReadShort(); MSG_ReadByte();
212 servers = alloca (net_message.cursize - 23);
213 memcpy (servers , net_message.data + 23, net_message.cursize - 23);
215 // Extract the IP addresses
216 while ((ipaddr = (servers[3] << 24) + (servers[2] << 16) + (servers[1] << 8) + servers[0]) != -1)
218 int port = (servers[5] << 8) + servers[4];
220 if (port == -1 || port == 0)
223 port = ((port >> 8) & 0xFF) + ((port & 0xFF) << 8);
224 sprintf (ipstring, "%u.%u.%u.%u:%hu",
225 ipaddr & 0xFF, (ipaddr >> 8) & 0xFF,
226 (ipaddr >> 16) & 0xFF, ipaddr >> 24,
228 dfunc->GetAddrFromName (ipstring, &svaddr);
230 Con_DPrintf("Requesting info from server %s\n", ipstring);
231 // Send a request at this address
232 SZ_Clear(&net_message);
233 MSG_WriteLong(&net_message, 0); // save space for the header, filled in later
234 MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
235 MSG_WriteString(&net_message, "QUAKE");
236 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
237 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
238 dfunc->Write(dfunc->controlSock, net_message.data, net_message.cursize, &svaddr);
239 SZ_Clear(&net_message);
241 if (servers[6] != '\\')