shithub: choc

Download patch

ref: d5f0ddc20b192cf1f17b27347dd467cddf493a6d
parent: 7355700d83fbab08c96fa8181b5aa3938464197e
author: Simon Howard <fraggle@gmail.com>
date: Thu Apr 6 16:48:35 EDT 2006

Add the ability to query the current state of servers, and '-query'
command line option to do so.

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 464

--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: d_main.c 455 2006-03-30 19:08:37Z fraggle $
+// $Id: d_main.c 464 2006-04-06 20:48:35Z fraggle $
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
@@ -184,7 +184,7 @@
 //-----------------------------------------------------------------------------
 
 
-static const char rcsid[] = "$Id: d_main.c 455 2006-03-30 19:08:37Z fraggle $";
+static const char rcsid[] = "$Id: d_main.c 464 2006-04-06 20:48:35Z fraggle $";
 
 #define	BGCOLOR		7
 #define	FGCOLOR		8
@@ -240,6 +240,7 @@
 #include "am_map.h"
 #include "net_client.h"
 #include "net_dedicated.h"
+#include "net_query.h"
 
 #include "p_setup.h"
 #include "r_local.h"
@@ -1357,6 +1358,16 @@
 
         // Never returns
     }
+
+    // Query network servers?
+
+    p = M_CheckParm("-query");
+
+    if (p > 0)
+    {
+        NET_QueryAddress(myargv[p+1]);
+    }
+
 
 #ifdef FEATURE_DEHACKED
     printf("DEH_Init: Init Dehacked support.\n");
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_defs.h 462 2006-04-06 19:31:45Z fraggle $
+// $Id: net_defs.h 464 2006-04-06 20:48:35Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -163,6 +163,8 @@
     NET_PACKET_TYPE_RELIABLE_ACK,
     NET_PACKET_TYPE_GAMEDATA_RESEND,
     NET_PACKET_TYPE_CONSOLE_MESSAGE,
+    NET_PACKET_TYPE_QUERY,
+    NET_PACKET_TYPE_QUERY_RESPONSE,
 } net_packet_type_t;
 
 typedef struct 
--- /dev/null
+++ b/src/net_query.c
@@ -1,0 +1,197 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// $Id: net_client.c 462 2006-04-06 19:31:45Z fraggle $
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//     Querying servers to find their current status.
+//
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "i_system.h"
+#include "i_timer.h"
+
+#include "net_common.h"
+#include "net_defs.h"
+#include "net_io.h"
+#include "net_packet.h"
+#include "net_query.h"
+#include "net_sdl.h"
+
+static net_context_t *query_context;
+static int num_responses;
+
+static void NET_Query_SendQuery(net_addr_t *addr)
+{
+    net_packet_t *request;
+
+    request = NET_NewPacket(10);
+    NET_WriteInt16(request, NET_PACKET_TYPE_QUERY);
+    NET_SendPacket(addr, request);
+    NET_FreePacket(request);
+}
+
+static void formatted_printf(int wide, char *s, ...)
+{
+    va_list args;
+    int i;
+    
+    va_start(args, s);
+    i = vprintf(s, args);
+    va_end(args);
+
+    while (i < wide) 
+    {
+        putchar(' ');
+        ++i;
+    } 
+}
+
+static char *GameDescription(GameMode_t mode, GameMission_t mission)
+{
+    switch (mode)
+    {
+        case shareware:
+            return "shareware";
+        case registered:
+            return "registered";
+        case retail:
+            return "ultimate";
+        case commercial:
+            if (mission == doom2)
+                return "doom2";
+            else if (mission == pack_tnt)
+                return "tnt";
+            else if (mission == pack_plut)
+                return "plutonia";
+        default:
+            return "unknown";
+    }
+}
+
+static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet)
+{
+    unsigned int packet_type;
+    char *server_version;
+    unsigned int in_game;
+    unsigned int num_players, max_players;
+    unsigned int servermode, servermission;
+    char *server_description;
+    int i;
+
+    if (!NET_ReadInt16(packet, &packet_type)
+     || !(server_version = NET_ReadString(packet))
+     || !NET_ReadInt8(packet, &in_game)
+     || !NET_ReadInt8(packet, &num_players)
+     || !NET_ReadInt8(packet, &max_players)
+     || !NET_ReadInt8(packet, &servermode)
+     || !NET_ReadInt8(packet, &servermission)
+     || !(server_description = NET_ReadString(packet)))
+    {
+        return;
+    }
+
+    if (num_responses <= 0)
+    {
+        // If this is the first response, print the table header
+
+        formatted_printf(18, "Address");
+        formatted_printf(8, "Players");
+        puts("Description");
+
+        for (i=0; i<70; ++i)
+            putchar('=');
+        putchar('\n');
+    }
+
+    formatted_printf(18, "%s: ", NET_AddrToString(addr));
+    formatted_printf(8, "%i/%i", num_players, max_players);
+
+    if (servermode != indetermined)
+    {
+        printf("(%s) ", GameDescription(servermode, servermission));
+    }
+
+    if (in_game)
+    {
+        printf("(game running) ");
+    }
+
+    NET_SafePuts(server_description);
+
+    ++num_responses;
+}
+
+static void NET_Query_GetResponse(void)
+{
+    net_addr_t *addr;
+    net_packet_t *packet;
+
+    if (NET_RecvPacket(query_context, &addr, &packet))
+    {
+        NET_Query_ParsePacket(addr, packet);
+    }
+}
+
+void NET_Query_Init(void)
+{
+    query_context = NET_NewContext();
+    NET_AddModule(query_context, &net_sdl_module);
+    net_sdl_module.InitClient();
+
+    num_responses = 0;
+}
+
+void NET_QueryAddress(char *addr)
+{
+    int start_time;
+    net_addr_t *net_addr;
+    
+    NET_Query_Init();
+
+    net_addr = NET_ResolveAddress(query_context, addr);
+
+    if (net_addr == NULL)
+    {
+        I_Error("NET_QueryAddress: Host '%s' not found!", addr);
+    }
+
+    printf("\nQuerying '%s'...\n\n", addr);
+
+    NET_Query_SendQuery(net_addr);
+
+    start_time = I_GetTimeMS();
+
+    while (num_responses <= 0 && I_GetTimeMS() < start_time + 5000)
+    {
+        NET_Query_GetResponse();
+        I_Sleep(100);
+    }
+
+    if (num_responses <= 0)
+    {
+        I_Error("No response from '%s'", addr);
+    }
+
+    exit(0);
+}
+
--- /dev/null
+++ b/src/net_query.h
@@ -1,0 +1,33 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// $Id: net_client.c 462 2006-04-06 19:31:45Z fraggle $
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//     Querying servers to find their current status.
+//
+
+#ifndef NET_QUERY_H
+#define NET_QUERY_H
+
+extern void NET_QueryAddress(char *addr);
+
+#endif /* #ifndef NET_QUERY_H */
+
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_server.c 461 2006-04-06 17:53:43Z fraggle $
+// $Id: net_server.c 464 2006-04-06 20:48:35Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -1058,7 +1058,43 @@
     NET_SV_SendTics(client, start, last);
 }
 
+// Send a response back to the client
 
+void NET_SV_SendQueryResponse(net_addr_t *addr)
+{
+    net_packet_t *reply;
+
+    reply = NET_NewPacket(64);
+    NET_WriteInt16(reply, NET_PACKET_TYPE_QUERY_RESPONSE);
+
+    // Version
+
+    NET_WriteString(reply, PACKAGE_STRING);
+
+    // Server state
+
+    NET_WriteInt8(reply, server_state);
+
+    // Number of players/maximum players
+
+    NET_WriteInt8(reply, NET_SV_NumClients());
+    NET_WriteInt8(reply, MAXPLAYERS);
+
+    // Game mode/mission
+
+    NET_WriteInt8(reply, sv_gamemode);
+    NET_WriteInt8(reply, sv_gamemission);
+
+    // Server description.  This is currently hard-coded.
+
+    NET_WriteString(reply, "Chocolate Doom server");
+
+    // Send it and we're done.
+
+    NET_SendPacket(addr, reply);
+    NET_FreePacket(reply);
+}
+
 // Process a packet received by the server
 
 static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
@@ -1083,6 +1119,10 @@
     {
         NET_SV_ParseSYN(packet, client, addr);
     }
+    else if (packet_type == NET_PACKET_TYPE_QUERY)
+    {
+        NET_SV_SendQueryResponse(addr);
+    }
     else if (client == NULL)
     {
         // Must come from a valid client; ignore otherwise
@@ -1299,6 +1339,7 @@
         if (NET_SV_NumClients() <= 0)
         {
             server_state = SERVER_WAITING_START;
+            sv_gamemode = indetermined;
         }
     }
     
@@ -1355,6 +1396,7 @@
     }
 
     server_state = SERVER_WAITING_START;
+    sv_gamemode = indetermined;
     server_initialised = true;
 }