Complete.Org: Mailing Lists: Archives: freeciv-dev: June 2005:
[Freeciv-Dev] (PR#13262) RFC: pubserver-in-a-diff
Home

[Freeciv-Dev] (PR#13262) RFC: pubserver-in-a-diff

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#13262) RFC: pubserver-in-a-diff
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Mon, 13 Jun 2005 12:49:38 -0700
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=13262 >

This patch implements the ./configure switch --enable-pubserver. When you
use it:
 * You cannot manually save games (for security reasons)
 * /write is disabled (for security reasons)
 * Whenever a new server session is started (from starting the server or
   restarting it), a new output directory is created at the --saves DIR
   address + a unique number (eg civserver --saves /tmp may give /tmp/12
   as directory). All savegames, cmdline output and gamelogs are put
   there.
 * The 'load' command is ALLOW_CTRL (not hack) and takes a game number,
   not a filename.
 * Some default settings are different, notably quitidle and saveturns
 * The savename setting is disabled, all savegames are called
   'civgame.sav', and only one savegame is created for each game session.

TODO
 * Make rulesetdir and /read work too.

DISCUSS:
 * Jason wants it to be a cmdline option instead. This is a bit hard the
   way it is currently done, which you will see from the patch.
 * Perhaps an automated game session reaper to clean out old sessions on
   server start/restart should be written.
 * A way to compile in an admin password?
 * More savegames?

  - Per

Index: configure.ac
===================================================================
RCS file: /home/freeciv/CVS/freeciv/configure.ac,v
retrieving revision 1.104
diff -u -r1.104 configure.ac
--- configure.ac        8 May 2005 13:31:24 -0000       1.104
+++ configure.ac        13 Jun 2005 19:38:40 -0000
@@ -41,6 +41,17 @@
 
 FC_CHECK_AUTH
 
+AC_ARG_ENABLE(pubserver,
+[  --enable-pubserver      compile for public server usage],
+[case "${enableval}" in
+  yes) pubserver=true ;;
+  no)  pubserver=false ;;
+  *)   AC_MSG_ERROR(bad value ${enableval} for --enable-pubserver) ;;
+esac], [pubserver=false])
+if test "$pubserver" = true ; then
+  AC_DEFINE(PUBSERVER, 1, [Compile for public server usage])
+fi
+
 dnl  no=do not compile server,  yes=compile server,  *=error
 AC_ARG_ENABLE(server,
 [  --disable-server        do not compile the server],
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.218
diff -u -r1.218 game.c
--- common/game.c       4 Jun 2005 22:57:24 -0000       1.218
+++ common/game.c       13 Jun 2005 19:38:41 -0000
@@ -233,7 +233,7 @@
   game.info.cooling       = 0;
   game.info.watchtower_extra_vision = GAME_DEFAULT_WATCHTOWER_EXTRA_VISION;
   game.info.allowed_city_names = GAME_DEFAULT_ALLOWED_CITY_NAMES;
-  game.info.save_nturns   = 10;
+  game.info.save_nturns   = GAME_DEFAULT_SAVETURNS;
 #ifdef HAVE_LIBZ
   game.info.save_compress_level = GAME_DEFAULT_COMPRESS_LEVEL;
 #else
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.193
diff -u -r1.193 game.h
--- common/game.h       10 Jun 2005 02:20:05 -0000      1.193
+++ common/game.h       13 Jun 2005 19:38:41 -0000
@@ -334,6 +334,11 @@
 #define GAME_DEFAULT_RULESETDIR      "default"
 
 #define GAME_DEFAULT_SAVE_NAME       "civgame"
+#ifdef PUBSERVER
+#define GAME_DEFAULT_SAVETURNS       1
+#else
+#define GAME_DEFAULT_SAVETURNS       10
+#endif
 
 #define GAME_DEFAULT_SKILL_LEVEL 3      /* easy */
 #define GAME_OLD_DEFAULT_SKILL_LEVEL 5  /* normal; for old save games */
Index: server/civserver.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/civserver.c,v
retrieving revision 1.230
diff -u -r1.230 civserver.c
--- server/civserver.c  3 Feb 2005 08:04:55 -0000       1.230
+++ server/civserver.c  13 Jun 2005 19:38:42 -0000
@@ -173,7 +173,8 @@
       sz_strlcpy(srvarg.serverid, option);
       free(option);
     } else if ((option = get_option_malloc("--saves", argv, &inx, argc))) {
-      srvarg.saves_pathname = option; /* Never freed. */
+      srvarg.saves_pathname = option; /* Base path. Never freed. */
+      sz_strlcpy(srvarg.final_savepath, option); /* Possibly changing path. */
     } else if (is_option("--version", argv[inx]))
       showvers = TRUE;
     else {
Index: server/commands.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/commands.c,v
retrieving revision 1.12
diff -u -r1.12 commands.c
--- server/commands.c   21 May 2005 19:40:25 -0000      1.12
+++ server/commands.c   13 Jun 2005 19:38:42 -0000
@@ -337,6 +337,16 @@
       "    --file <filename>\n"
       "and use the 'start' command once players have reconnected.")
   },
+#ifdef PUBSERVER
+  {"load",      ALLOW_CTRL,
+   /* TRANS: translate text between <> only */
+   N_("load\n"
+      "load <game number>"),
+   N_("Load the latest savegame from a public server game."),
+   N_("Load a game from the public server. Any current data including players, 
"
+      "rulesets and server options are lost.\n")
+  },
+#else
   {"load",      ALLOW_HACK,
    /* TRANS: translate text between <> only */
    N_("load\n"
@@ -345,6 +355,7 @@
    N_("Load a game from <file-name>. Any current data including players, "
       "rulesets and server options are lost.\n")
   },
+#endif
   {"read",     ALLOW_HACK,
    /* TRANS: translate text between <> only */
    N_("read <file-name>"),
Index: server/settings.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settings.c,v
retrieving revision 1.26
diff -u -r1.26 settings.c
--- server/settings.c   9 Jun 2005 18:24:48 -0000       1.26
+++ server/settings.c   13 Jun 2005 19:38:42 -0000
@@ -951,7 +951,7 @@
          N_("Turns per auto-save"),
          N_("The game will be automatically saved per this number of "
             "turns. Zero means never auto-save."), NULL, 
-         0, 200, 10)
+         0, 200, GAME_DEFAULT_SAVETURNS)
 
   /* Could undef entire option if !HAVE_LIBZ, but this way users get to see
    * what they're missing out on if they didn't compile with zlib?  --dwp
@@ -979,7 +979,7 @@
          GAME_NO_COMPRESS_LEVEL, GAME_NO_COMPRESS_LEVEL, 
          GAME_NO_COMPRESS_LEVEL)
 #endif
-
+#ifndef PUBSERVER
   GEN_STRING("savename", game.save_name,
             SSET_META, SSET_INTERNAL, SSET_VITAL, SSET_SERVER_ONLY,
             N_("Auto-save name prefix"),
@@ -987,7 +987,7 @@
                "\"<prefix><year>.sav\". This setting sets "
                "the <prefix> part."), NULL,
             GAME_DEFAULT_SAVE_NAME)
-
+#endif
   GEN_BOOL("scorelog", game.scorelog,
           SSET_META, SSET_INTERNAL, SSET_SITUATIONAL, SSET_SERVER_ONLY,
           N_("Whether to log player statistics"),
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.269
diff -u -r1.269 srv_main.c
--- server/srv_main.c   9 Jun 2005 18:30:13 -0000       1.269
+++ server/srv_main.c   13 Jun 2005 19:38:43 -0000
@@ -17,10 +17,14 @@
 
 #include <assert.h>
 #include <ctype.h>
+#include <dirent.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
@@ -166,6 +170,7 @@
 
   /* init server arguments... */
 
+  srvarg.pubserver_serial = 0;
   srvarg.metaserver_no_send = DEFAULT_META_SERVER_NO_SEND;
   sz_strlcpy(srvarg.metaserver_addr, DEFAULT_META_SERVER_ADDR);
 
@@ -179,8 +184,13 @@
   srvarg.load_filename[0] = '\0';
   srvarg.script_filename = NULL;
   srvarg.saves_pathname = "";
+  srvarg.final_savepath[0] = '\0';
 
+#ifdef PUBSERVER
+  srvarg.quitidle = 30;
+#else
   srvarg.quitidle = 0;
+#endif
 
   srvarg.auth_enabled = FALSE;
   srvarg.auth_allow_guests = FALSE;
@@ -726,11 +739,15 @@
     *dot = '\0';
   }
 
+#ifndef PUBSERVER
   /* If orig_filename is NULL or empty, use "civgame.info.year>m". */
   if (filename[0] == '\0'){
     my_snprintf(filename, sizeof(filename),
        "%s%+05dm", game.save_name, game.info.year);
   }
+#else
+  sz_strlcpy(filename, game.save_name);
+#endif
   
   timer_cpu = new_timer_start(TIMER_CPU, TIMER_ACTIVE);
   timer_user = new_timer_start(TIMER_USER, TIMER_ACTIVE);
@@ -750,9 +767,9 @@
     char tmpname[600];
 
     /* Ensure the saves directory exists. */
-    make_dir(srvarg.saves_pathname);
+    make_dir(srvarg.final_savepath);
 
-    sz_strlcpy(tmpname, srvarg.saves_pathname);
+    sz_strlcpy(tmpname, srvarg.final_savepath);
     if (tmpname[0] != '\0') {
       sz_strlcat(tmpname, "/");
     }
@@ -760,10 +777,14 @@
     sz_strlcpy(filename, tmpname);
   }
 
-  if(!section_file_save(&file, filename, game.info.save_compress_level))
+  if (!section_file_save(&file, filename, game.info.save_compress_level)) {
     con_write(C_FAIL, _("Failed saving game as %s"), filename);
-  else
+  }
+#ifndef PUBSERVER
+  else {
     con_write(C_OK, _("Game saved as %s"), filename);
+  }
+#endif
 
   section_file_free(&file);
 
@@ -1766,6 +1787,37 @@
 
   /* Run server loop */
   while (TRUE) {
+#ifdef PUBSERVER
+    /* Find a new empty directory number. We operate from
+     * whereever we are started. */
+    DIR *dir;
+    int i = 0;
+    char path[20], gamelogfile[40], conlogfile[40];
+
+    /* Find first unused directory */
+    dir = NULL;
+    do {
+      my_snprintf(path, sizeof(path), "%d", i);
+      dir = opendir(path);
+      if (i >= 10000) {
+        die("We either have in excess of 10k games, or a path problem. "
+            "Clean up or fix it! (%s)", path);
+      }
+      i++;
+    } while (dir != NULL);
+    make_dir(path);
+    srvarg.pubserver_serial = i;
+    sz_strlcpy(srvarg.final_savepath, path);
+    /* Redirect output to saves directory */
+    my_snprintf(gamelogfile, sizeof(gamelogfile), "%s/gamelog.txt", 
+                srvarg.final_savepath);
+    my_snprintf(conlogfile, sizeof(conlogfile), "%s/cmdline.txt", 
+                srvarg.final_savepath);
+    con_log_init(conlogfile, srvarg.loglevel);
+    gamelog_init(gamelogfile);
+    notify_player(NULL, _("You are playing public game %d."), i);
+#endif
+
     srv_loop();
 
     send_game_state(game.game_connections, CLIENT_GAME_OVER_STATE);
Index: server/srv_main.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.h,v
retrieving revision 1.34
diff -u -r1.34 srv_main.h
--- server/srv_main.h   9 Jun 2005 18:24:48 -0000       1.34
+++ server/srv_main.h   13 Jun 2005 19:38:43 -0000
@@ -22,6 +22,7 @@
 BV_DEFINE(bv_draw, MAX_NUM_PLAYERS);
 
 struct server_arguments {
+  int pubserver_serial;
   /* metaserver information */
   bool metaserver_no_send;
   char metaserver_addr[256];
@@ -33,11 +34,12 @@
   /* the log level */
   int loglevel;
   /* filenames */
-  char *log_filename;
-  char *gamelog_filename;
+  char *log_filename;      /* ignored by pubserver */
+  char *gamelog_filename;  /* ignored by pubserver */
   char load_filename[512]; /* FIXME: may not be long enough? use MAX_PATH? */
   char *script_filename;
-  char *saves_pathname;
+  char *saves_pathname;     /* base path; used by pubserver for all output */
+  char final_savepath[512]; /* may be changed by pubserver code */
   char serverid[256];
   /* quit if there no players after a given time interval */
   int quitidle;
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.419
diff -u -r1.419 stdinhand.c
--- server/stdinhand.c  9 Jun 2005 18:24:48 -0000       1.419
+++ server/stdinhand.c  13 Jun 2005 19:38:44 -0000
@@ -755,10 +755,16 @@
 **************************************************************************/
 static bool save_command(struct connection *caller, char *arg, bool check)
 {
+#ifdef PUBSERVER
+  cmd_reply(CMD_SAVE, caller, C_FAIL,
+            _("You cannot save games manually on this server."));
+  return FALSE;
+#else
   if (!check) {
     save_game(arg, "User request");
   }
   return TRUE;
+#endif
 }
 
 /**************************************************************************
@@ -1017,6 +1023,7 @@
   return read_init_script(caller, arg);
 }
 
+#ifndef PUBSERVER
 /**************************************************************************
 ...
 (Should this take a 'caller' argument for output? --dwp)
@@ -1098,6 +1105,7 @@
        _("Could not write script file '%s'."), real_filename);
   }
 }
+#endif
 
 /**************************************************************************
 ...
@@ -1105,10 +1113,15 @@
 **************************************************************************/
 static bool write_command(struct connection *caller, char *arg, bool check)
 {
+#ifdef PUBSERVER
+  cmd_reply(CMD_WRITE_SCRIPT, caller, C_OK, _("You cannot write on this 
server."));
+  return FALSE;
+#else 
   if (!check) {
     write_init_script(arg);
   }
   return TRUE;
+#endif
 }
 
 /**************************************************************************
@@ -3135,7 +3148,23 @@
 {
   struct timer *loadtimer, *uloadtimer;  
   struct section_file file;
-  char arg[strlen(filename) + 1];
+#ifdef PUBSERVER
+  char arg[512 + strlen(filename)];
+
+  {
+    int i;
+
+    /* filename must be a valid number */
+    if (!filename || sscanf(filename, "%d", &i) != 1 || filename[0] == '\0') {
+      cmd_reply(CMD_LOAD, caller, C_FAIL, _("Usage: load <game number>"));
+      return FALSE;
+    }
+  }
+  my_snprintf(arg, sizeof(arg), "%s%s%s/civgame.sav%s", srvarg.saves_pathname, 
+              srvarg.saves_pathname[0] == '\0' ? "" : "/",
+              filename, game.info.save_compress_level > 0 ? ".gz" : "");
+#else
+  char arg[strlen(filename) + 1];  
 
   /* We make a local copy because the parameter might be a pointer to 
    * srvarg.load_filename, which we edit down below. */
@@ -3146,6 +3175,7 @@
     send_load_game_info(FALSE);
     return FALSE;
   }
+#endif
 
   if (server_state != PRE_GAME_STATE) {
     cmd_reply(CMD_LOAD, caller, C_FAIL, _("Can't load a game while another "

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#13262) RFC: pubserver-in-a-diff, Per I. Mathisen <=