diff --git a/engine/server/sv_master.c b/engine/server/sv_master.c
index 881fedbdb..54945c542 100644
--- a/engine/server/sv_master.c
+++ b/engine/server/sv_master.c
@@ -553,180 +553,209 @@ static void SVM_Init(void)
);
}
-vfsfile_t *SVM_GenerateIndex(const char *requesthost, const char *fname, const char **mimetype, const char *query)
+vfsfile_t *SVM_Generate_Gamelist(const char **mimetype, const char *query)
{
+ vfsfile_t *f = VFSPIPE_Open(1, false);
+ char tmpbuf[256];
+ char hostname[1024];
+ svm_game_t *game;
+ svm_server_t *server;
+ unsigned clients=0,bots=0,specs=0, totalclients=0, totalbots=0, totalspecs=0;
+
+ VFS_PRINTF(f, "%s", master_css);
+ VFS_PRINTF(f, "
%s
\n", sv_hostname.string);
+ VFS_PRINTF(f, "\n");
+ VFS_PRINTF(f, "Active Games | Players | Server Count |
\n");
+ for (game = svm.firstgame; game; game = game->next)
+ {
+ for (clients=0,bots=0,specs=0, server = game->firstserver; server; server = server->next)
+ {
+ clients += server->clients;
+ bots += server->bots;
+ specs += server->spectators;
+ }
+ if (game->numservers || !sv_hideinactivegames.ival) //only show active servers
+ {
+ QuakeCharsToHTML(tmpbuf, sizeof(tmpbuf), game->name, true);
+ VFS_PRINTF(f, "%s | %u player%s", game->name, query?"?":"", query?query:"", tmpbuf, clients, clients==1?"":"s");
+ if (bots)
+ VFS_PRINTF(f, ", %u bot%s", bots, bots==1?"":"s");
+ if (specs)
+ VFS_PRINTF(f, ", %u spectator%s", specs, specs==1?"":"s");
+ VFS_PRINTF(f, " | %u server%s |
\n", (unsigned)game->numservers, game->numservers==1?"":"s");
+ }
+ totalclients += clients;
+ totalbots += bots;
+ totalspecs += specs;
+ }
+ VFS_PRINTF(f, "
\n");
+ VFS_PRINTF(f, "%u game%s", (unsigned)svm.numgames, svm.numgames==1?"":"s");
+ if (totalclients)
+ VFS_PRINTF(f, ", %u player%s", totalclients, totalclients==1?"":"s");
+ if (totalbots)
+ VFS_PRINTF(f, ", %u bot%s", totalbots, totalbots==1?"":"s");
+ if (totalspecs)
+ VFS_PRINTF(f, ", %u spectator%s", totalspecs, totalspecs==1?"":"s");
+ VFS_PRINTF(f, ", %u server%s
\n", (unsigned)svm.numservers, svm.numservers==1?"":"s");
+
+ net_from.prot = NP_DGRAM;
+ VFS_PRINTF(f, "Your IP is %s
\n", NET_BaseAdrToString(hostname, sizeof(hostname), &net_from));
+
+ *mimetype = "text/html";
+ return f;
+}
+vfsfile_t *SVM_Generate_Serverinfo(const char **mimetype, const char *serveraddr, const char *query)
+{
+ vfsfile_t *f = VFSPIPE_Open(1, false);
+ char tmpbuf[256];
+ char hostname[1024];
+ svm_server_t *server;
+ netadr_t adr[64];
+ int count;
+
+ VFS_PRINTF(f, "%s", master_css);
+ VFS_PRINTF(f, "Single Server Info
\n");
+
+ VFS_PRINTF(f, "\n");
+ VFS_PRINTF(f, "Game | Address | Hostname | Mod dir | Mapname | Players |
\n");
+ //FIXME: block dns lookups here?
+ count = NET_StringToAdr2(serveraddr, 0, adr, countof(adr), NULL);
+ while(count-->0)
+ {
+ server = SVM_GetServer(&adr[count]);
+ if (server)
+ {
+ QuakeCharsToHTML(hostname, sizeof(hostname), server->hostname, false);
+ VFS_PRINTF(f, "%s | %s | %s%s | %s | %s | %u/%u |
\n", server->game?server->game->name:"Unknown", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), (server->needpass&1)?"🔒":"", hostname, server->gamedir, server->mapname, server->clients, server->maxclients);
+ }
+ else
+ VFS_PRINTF(f, "? | %s | ? | ? | ? | ?/? |
\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &adr[count]));
+ }
+ VFS_PRINTF(f, "
\n");
+
+ *mimetype = "text/html";
+ return f;
+}
+
+vfsfile_t *SVM_Generate_Serverlist(const char **mimetype, const char *masteraddr, const char *gamename, const char *query)
+{
+ vfsfile_t *f = VFSPIPE_Open(1, false);
char tmpbuf[256];
char hostname[1024];
const char *url;
svm_game_t *game;
svm_server_t *server;
+ unsigned clients=0,bots=0,specs=0;
+
+ qboolean showver = query && !!strstr(query, "ver=1");
+ game = SVM_FindGame(gamename, false);
+
+ VFS_PRINTF(f, "%s", master_css);
+
+ if (!strcmp(gamename, "UNKNOWN"))
+ {
+ VFS_PRINTF(f, "Unresponsive Servers
\n");
+ VFS_PRINTF(f, "These servers have sent a heartbeat but have failed to respond to an appropriate query from a different port. This can happen when:"
+ "- Server is firewalled and all inbound packets are dropped. Try reconfiguring your firewall to allow packets to that process or port.
"
+ "- An intermediate router implements an Address/Port-Dependant-Filtering NAT. Try setting up port forwarding.
"
+ "- Outgoing connections are asynchronous with regard to port forwarding. Such servers will show with arbitrary ephemerial ports. Docker: you can supposedly work around this with --net=host.
"
+ "- Plain and simple packet loss, servers in this state for less than 5 mins may still be fine.
"
+ "- Server crashed or was reconfigured before it could respond.
"
+ "- MTU limits with failed defragmentation.
"
+ "- Routing table misconfiguration.
"
+ "- Other.
"
+ "
\n");
+ }
+ else
+ VFS_PRINTF(f, "Servers for %s
\n", QuakeCharsToHTML(tmpbuf, sizeof(tmpbuf), gamename, true));
+
+ if(game)
+ {
+ SVM_SortServers(game);
+
+ VFS_PRINTF(f, "\n");
+ VFS_PRINTF(f, "Address | Hostname | Gamedir | Mapname | Players | ");
+ if (showver)
+ VFS_PRINTF(f, "Version | ");
+ VFS_PRINTF(f, "
\n");
+ for (server = game->firstserver; server; server = server->next)
+ {
+ if (server->brokerid)
+ {
+ url = tmpbuf;
+ Q_snprintfz(tmpbuf, sizeof(tmpbuf), "rtc://%s/%s", masteraddr, server->brokerid);
+ }
+ else
+ url = NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr);
+ QuakeCharsToHTML(hostname, sizeof(hostname), server->hostname, false);
+ VFS_PRINTF(f, "%s | %s%s%s | %s | %s | %u", url, (server->needpass&1)?"🔒":"", (server->coop&1)?"🚸":"", hostname, server->gamedir, server->mapname, server->clients);
+ if (server->bots)
+ VFS_PRINTF(f, "+%ub", server->bots);
+ VFS_PRINTF(f, "/%u", server->maxclients);
+ if (server->spectators)
+ VFS_PRINTF(f, ", %us", server->spectators);
+ VFS_PRINTF(f, " | ");
+ if (showver)
+ VFS_PRINTF(f, "%s | ", server->version);
+ VFS_PRINTF(f, "
\n");
+ clients += server->clients;
+ bots += server->bots;
+ specs += server->spectators;
+ }
+ VFS_PRINTF(f, "
\n");
+ VFS_PRINTF(f, "%u server%s", (unsigned)game->numservers, game->numservers==1?"":"s");
+ if (clients)
+ VFS_PRINTF(f, ", %u client%s", (unsigned)clients, clients==1?"":"s");
+ if (bots)
+ VFS_PRINTF(f, ", %u bot%s", (unsigned)bots, bots==1?"":"s");
+ if (specs)
+ VFS_PRINTF(f, ", %u spectator%s", (unsigned)specs, specs==1?"":"s");
+ VFS_PRINTF(f, "\n");
+ }
+ else
+ VFS_PRINTF(f, "Protocol '%s' is not known\n", gamename);
+
+ *mimetype = "text/html";
+ return f;
+}
+
+vfsfile_t *SVM_Generate_Rawlist(const char **mimetype, const char *masteraddr, const char *gamename, const char *query)
+{ //just spews all
+ char tmpbuf[256];
+ svm_game_t *game;
+ svm_server_t *server;
+ vfsfile_t *f = VFSPIPE_Open(1, false);
+
+ COM_StripExtension(gamename, tmpbuf, sizeof(tmpbuf));
+ game = SVM_FindGame(tmpbuf, false);
+
+ f = VFSPIPE_Open(1, false);
+ VFS_PRINTF(f, "#Server list for \"%s\"\n", tmpbuf);
+ for (server = (game?game->firstserver:NULL); server; server = server->next)
+ {
+ if (server->brokerid)
+ VFS_PRINTF(f, "rtc://%s/%s \\maxclients\\%u\\clients\\%u\\bots\\%u\\hostname\\%s\\modname\\%s\\mapname\\%s\\needpass\\%i\n", masteraddr, server->brokerid, server->maxclients, server->clients, server->bots, server->hostname, server->gamedir, server->mapname, server->needpass);
+ else
+ VFS_PRINTF(f, "%s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr));
+ }
+
+ *mimetype = "text/plain";
+ return f;
+}
+
+vfsfile_t *SVM_GenerateIndex(const char *requesthost, const char *fname, const char **mimetype, const char *query)
+{
vfsfile_t *f = NULL;
- unsigned clients=0,bots=0,specs=0, totalclients=0, totalbots=0, totalspecs=0;
if (!master_css)
SVM_Init();
if (!strcmp(fname, "index.html"))
- {
- f = VFSPIPE_Open(1, false);
- VFS_PRINTF(f, "%s", master_css);
- VFS_PRINTF(f, "%s
\n", sv_hostname.string);
- VFS_PRINTF(f, "\n");
- VFS_PRINTF(f, "Active Games | Players | Server Count |
\n");
- for (game = svm.firstgame; game; game = game->next)
- {
- for (clients=0,bots=0,specs=0, server = game->firstserver; server; server = server->next)
- {
- clients += server->clients;
- bots += server->bots;
- specs += server->spectators;
- }
- if (game->numservers || !sv_hideinactivegames.ival) //only show active servers
- {
- QuakeCharsToHTML(tmpbuf, sizeof(tmpbuf), game->name, true);
- VFS_PRINTF(f, "%s | %u player%s", game->name, query?"?":"", query?query:"", tmpbuf, clients, clients==1?"":"s");
- if (bots)
- VFS_PRINTF(f, ", %u bot%s", bots, bots==1?"":"s");
- if (specs)
- VFS_PRINTF(f, ", %u spectator%s", specs, specs==1?"":"s");
- VFS_PRINTF(f, " | %u server%s |
\n", (unsigned)game->numservers, game->numservers==1?"":"s");
- }
- totalclients += clients;
- totalbots += bots;
- totalspecs += specs;
- }
- VFS_PRINTF(f, "
\n");
- VFS_PRINTF(f, "%u game%s", (unsigned)svm.numgames, svm.numgames==1?"":"s");
- if (totalclients)
- VFS_PRINTF(f, ", %u player%s", totalclients, totalclients==1?"":"s");
- if (totalbots)
- VFS_PRINTF(f, ", %u bot%s", totalbots, totalbots==1?"":"s");
- if (totalspecs)
- VFS_PRINTF(f, ", %u spectator%s", totalspecs, totalspecs==1?"":"s");
- VFS_PRINTF(f, ", %u server%s
\n", (unsigned)svm.numservers, svm.numservers==1?"":"s");
-
- net_from.prot = NP_DGRAM;
- VFS_PRINTF(f, "Your IP is %s
\n", NET_BaseAdrToString(hostname, sizeof(hostname), &net_from));
-
- *mimetype = "text/html";
- }
+ f = SVM_Generate_Gamelist(mimetype, query);
else if (!strncmp(fname, "server/", 7))
- {
- netadr_t adr[64];
- int count;
-
- f = VFSPIPE_Open(1, false);
- VFS_PRINTF(f, "%s", master_css);
- VFS_PRINTF(f, "Single Server Info
\n");
-
- VFS_PRINTF(f, "\n");
- VFS_PRINTF(f, "Game | Address | Hostname | Mod dir | Mapname | Players |
\n");
- //FIXME: block dns lookups here?
- count = NET_StringToAdr2(fname+7, 0, adr, countof(adr), NULL);
- while(count-->0)
- {
- server = SVM_GetServer(&adr[count]);
- if (server)
- {
- QuakeCharsToHTML(hostname, sizeof(hostname), server->hostname, false);
- VFS_PRINTF(f, "%s | %s | %s%s | %s | %s | %u/%u |
\n", server->game?server->game->name:"Unknown", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), (server->needpass&1)?"🔒":"", hostname, server->gamedir, server->mapname, server->clients, server->maxclients);
- }
- else
- VFS_PRINTF(f, "? | %s | ? | ? | ? | ?/? |
\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &adr[count]));
- }
- VFS_PRINTF(f, "
\n");
-
- *mimetype = "text/html";
- }
+ f = SVM_Generate_Serverinfo(mimetype, fname+7, query);
else if (!strncmp(fname, "game/", 5))
- {
- qboolean showver = query && !!strstr(query, "ver=1");
- const char *gamename = fname+5;
- game = SVM_FindGame(gamename, false);
-
- f = VFSPIPE_Open(1, false);
- VFS_PRINTF(f, "%s", master_css);
-
- if (!strcmp(gamename, "UNKNOWN"))
- {
- VFS_PRINTF(f, "Unresponsive Servers
\n");
- VFS_PRINTF(f, "These servers have sent a heartbeat but have failed to respond to an appropriate query from a different port. This can happen when:"
- "- Server is firewalled and all inbound packets are dropped. Try reconfiguring your firewall to allow packets to that process or port.
"
- "- An intermediate router implements an Address/Port-Dependant-Filtering NAT. Try setting up port forwarding.
"
- "- Outgoing connections are asynchronous with regard to port forwarding. Such servers will show with arbitrary ephemerial ports. Docker: you can supposedly work around this with --net=host.
"
- "- Plain and simple packet loss, servers in this state for less than 5 mins may still be fine.
"
- "- Server crashed or was reconfigured before it could respond.
"
- "- MTU limits with failed defragmentation.
"
- "- Routing table misconfiguration.
"
- "- Other.
"
- "
\n");
- }
- else
- VFS_PRINTF(f, "Servers for %s
\n", QuakeCharsToHTML(tmpbuf, sizeof(tmpbuf), gamename, true));
-
- if(game)
- {
- SVM_SortServers(game);
-
- VFS_PRINTF(f, "\n");
- VFS_PRINTF(f, "Address | Hostname | Gamedir | Mapname | Players | ");
- if (showver)
- VFS_PRINTF(f, "Version | ");
- VFS_PRINTF(f, "
\n");
- for (server = game->firstserver; server; server = server->next)
- {
- if (server->brokerid)
- {
- url = tmpbuf;
- Q_snprintfz(tmpbuf, sizeof(tmpbuf), "rtc://%s/%s", requesthost, server->brokerid);
- }
- else
- url = NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr);
- QuakeCharsToHTML(hostname, sizeof(hostname), server->hostname, false);
- VFS_PRINTF(f, "%s | %s%s%s | %s | %s | %u", url, (server->needpass&1)?"🔒":"", (server->coop&1)?"🚸":"", hostname, server->gamedir, server->mapname, server->clients);
- if (server->bots)
- VFS_PRINTF(f, "+%ub", server->bots);
- VFS_PRINTF(f, "/%u", server->maxclients);
- if (server->spectators)
- VFS_PRINTF(f, ", %us", server->spectators);
- VFS_PRINTF(f, " | ");
- if (showver)
- VFS_PRINTF(f, "%s | ", server->version);
- VFS_PRINTF(f, "
\n");
- clients += server->clients;
- bots += server->bots;
- specs += server->spectators;
- }
- VFS_PRINTF(f, "
\n");
- VFS_PRINTF(f, "%u server%s", (unsigned)game->numservers, game->numservers==1?"":"s");
- if (clients)
- VFS_PRINTF(f, ", %u client%s", (unsigned)clients, clients==1?"":"s");
- if (bots)
- VFS_PRINTF(f, ", %u bot%s", (unsigned)bots, bots==1?"":"s");
- if (specs)
- VFS_PRINTF(f, ", %u spectator%s", (unsigned)specs, specs==1?"":"s");
- VFS_PRINTF(f, "\n");
- }
- else
- VFS_PRINTF(f, "Protocol '%s' is not known\n", gamename);
-
- *mimetype = "text/html";
- }
+ f = SVM_Generate_Serverlist(mimetype, requesthost, fname+5, query);
else if (!strncmp(fname, "raw/", 4))
- { //just spews all
- COM_StripExtension(fname+4, tmpbuf, sizeof(tmpbuf));
- game = SVM_FindGame(tmpbuf, false);
-
- f = VFSPIPE_Open(1, false);
- VFS_PRINTF(f, "#Server list for \"%s\"\n", tmpbuf);
- for (server = (game?game->firstserver:NULL); server; server = server->next)
- {
- if (server->brokerid)
- VFS_PRINTF(f, "rtc:///%s \\maxclients\\%u\\clients\\%u\\bots\\%u\\hostname\\%s\\modname\\%s\\mapname\\%s\\needpass\\%i\n", server->brokerid, server->maxclients, server->clients, server->bots, server->hostname, server->gamedir, server->mapname, server->needpass);
- else
- VFS_PRINTF(f, "%s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr));
- }
-
- *mimetype = "text/plain";
- }
+ f = SVM_Generate_Rawlist(mimetype, requesthost, fname+4, query);
return f;
}
@@ -1255,6 +1284,7 @@ static void SVM_ProcessUDPPacket(void)
{ //response from a FTE-master request (lots of IPs from a 'slave' master that we're stealing)
netadr_t a = {NA_INVALID};
msg_readcount = 4+21; //grr
+ msg_badread = false;
svm.total.heartbeats++;
for (;;)
{