[twilight-commits] r11248 - in trunk/dpmaster: . doc src testsuite

molivier at icculus.org molivier at icculus.org
Mon Jul 18 17:17:24 EDT 2011


Author: molivier
Date: 2011-07-18 17:17:24 -0400 (Mon, 18 Jul 2011)
New Revision: 11248

Added:
   trunk/dpmaster/changelog.txt
   trunk/dpmaster/doc/manual.txt
   trunk/dpmaster/testsuite/test-flood_protection.pl
Modified:
   trunk/dpmaster/doc/techinfo.txt
   trunk/dpmaster/readme.txt
   trunk/dpmaster/src/clients.c
   trunk/dpmaster/src/common.c
   trunk/dpmaster/src/common.h
   trunk/dpmaster/src/dpmaster.c
   trunk/dpmaster/src/servers.c
   trunk/dpmaster/src/system.c
   trunk/dpmaster/src/system.h
   trunk/dpmaster/testsuite/query_remote_master.pl
   trunk/dpmaster/testsuite/testlib.pm
Log:
Reduced the number of hash tables (one for all servers, and one for all clients). Moved most of the contents of readme.txt in 2 new files, with some minor editings here and there. Made the test duration an optional parameter to Test_Run(). Added a basic test for the flood protection. Fixed the parsing of the flood protection parameters

Added: trunk/dpmaster/changelog.txt
===================================================================
--- trunk/dpmaster/changelog.txt	                        (rev 0)
+++ trunk/dpmaster/changelog.txt	2011-07-18 21:17:24 UTC (rev 11248)
@@ -0,0 +1,120 @@
+
+                         Dpmaster, an open master server
+                         -------------------------------
+
+                                Version history
+                                ---------------
+
+
+* Version 2.2-dev:
+  - Flood protection against abusive clients, by Timothee Besset
+  - New system for managing game properties (see GAME PROPERTIES in manual.txt)
+  - Support for RtCW and WoET, using the game properties
+  - Shutdown heartbeats and unknown heartbeats are now ignored
+  - The chroot jail was preventing daemonization (fixed thanks to LordHavoc)
+  - The game type was incorrect when printing the server list in the log
+  - Less debug output when creating a getserversResponse in verbose mode
+
+* Version 2.1:
+  - A gametype value can now be any string, not just a number
+
+* Version 2.0:
+  - Gametype filter support in the server list queries (see techinfo.txt)
+  - New option "--game-policy" to filter games (see GAME POLICY in manual.txt)
+  - IPv6 support, including 2 new messages types (see techinfo.txt)
+  - Logging support (see LOGGING in manual.txt)
+  - Only the last packet of a getservers response gets an EOT mark now
+  - The default number of servers is now 4096
+  - Improved listening interface option (see LISTENING INTERFACES in manual.txt)
+  - Long format for all command line options (see SYNTAX & OPTIONS in
+    readme.txt)
+  - The server lists are now sent in a semi-random order, for fairness
+  - The new hash function supports up to 16-bit hashes
+  - The default hash size has been increased to 10 bits
+  - 0 is no longer an invalid hash size
+  - New option "--allow-loopback", for debugging purposes only!
+  - New option "--hash-ports", for debugging purposes only!
+  - Various updates and improvements in the documentation
+  - No warning is printed anymore if a server changes its game name
+  - No longer tolerates several mapping declarations for the same address
+  - A lot of minor changes and fixes in the code
+  - The test suite now requires the Socket6 Perl module to run
+
+* Version 1.7:
+  - There's now a maximum number of servers per IP address (default: 32)
+  - New option to set the maximum number of servers per IP address (-N)
+  - The maximum number of servers recorded by default is now 1024
+  - The default hash size has been increased from 6 bits to 8 bits
+  - A few Perl scripts have been added to provide basic automated testing
+  - A rare bug where a server was occasionally skipped was fixed
+  - The compilation with MS Visual Studio 2005 is fixed
+  - Protocol numbers less than or equal to 0 are now handled correctly
+  - Servers can no longer keep their slots without sending infoResponses
+  - Games having a name starting with a number are now handled correctly
+  - A few minor memory leaks were removed in the address mapping init code
+  - Additional checks of the command line options and the messages syntax
+  - The requirement of a "clients" value in infoResponses is now enforced
+  - The "infoResponse" description in techinfo.txt has been corrected
+  - The "heartbeat" description in techinfo.txt has been corrected
+  - The time is now printed to the console each time a packet is received
+  - Made it clear in the doc that any game can be supported out of the box
+
+* Version 1.6:
+  - Several getserversResponse may now be sent for a single getservers
+  - A getserversResponse packet can no longer exceed 1400 bytes
+  - The maximum number of servers recorded by default has doubled (now 256)
+  - The default hash size has been increased from 5 bits to 6 bits
+  - Several updates and corrections in the documentation
+
+* Version 1.5.1:
+  - Compilation on FreeBSD was fixed
+  - A couple of minor changes in "COMPILING DPMASTER" (in techinfo.txt)
+
+* Version 1.5:
+  - Address mapping added (see ADDRESS MAPPING in manual.txt)
+  - Servers on a loopback address are accepted again if they have a mapping
+  - A valid "infoReponse" is now rejected if its challenge has timed out
+  - The size of the challenge sent with "getinfo" has been made random
+  - A timed-out server is now removed as soon as a new server needs a slot
+  - Several little changes in the printings to make them more informative
+  - A technical documentation was added
+  - Compiling dpmaster with MSVC works again
+
+* Version 1.4:
+  - Dpmaster now quits if it can't chroot, switch privileges or daemonize
+  - Packets coming from a loopback address are now rejected with a warning
+  - Listen address option added (-l)
+  - Modified Makefile to please BSD make
+
+* Version 1.3.1:
+  - SECURITY WARNING: 2 exploitable buffer overflows were fixed
+  - Verbose option parsing fixed
+  - Paranoid buffer overflow checkings added, in case of future code changes
+
+* Version 1.3:
+  - Ability to support any game which uses DP master protocol (ex: QFusion)
+
+* Version 1.2.1:
+  - A major bug was fixed (a NULL pointer dereference introduced in v1.2)
+
+* Version 1.2:
+  - A major bug was fixed (an infinite loop in HandleGetServers)
+
+* Version 1.1:
+  - A lot of optimizations and tweakings
+  - Verbose option added (-v)
+  - Hash size option added (-H)
+  - Daemonization option added on UNIXes (-D)
+  - Chrooting and privileges dropping when running as root added on UNIXes
+  - MinGW cross-compilation support added
+
+* Version 1.01:
+  - A major bug was fixed. Most of the servers weren't sent to the clients
+
+* Version 1.0 :
+  - First publicly available version
+
+
+--
+Mathieu Olivier
+molivier, at users.sourceforge.net

Added: trunk/dpmaster/doc/manual.txt
===================================================================
--- trunk/dpmaster/doc/manual.txt	                        (rev 0)
+++ trunk/dpmaster/doc/manual.txt	2011-07-18 21:17:24 UTC (rev 11248)
@@ -0,0 +1,386 @@
+
+                         Dpmaster, an open master server
+                         -------------------------------
+
+                                  User's manual
+                                  -------------
+
+
+1) ABOUT THIS FILE
+2) SECURITY
+3) OUTPUT AND VERBOSITY LEVELS
+4) LOGGING
+5) GAME POLICY
+6) GAME PROPERTIES
+7) FLOOD PROTECTION
+8) ADDRESS MAPPING
+9) LISTENING INTERFACES
+
+
+1) ABOUT THIS FILE:
+
+This file contains detailed information about how to configure and run dpmaster.
+If you haven't already read the "readme.txt" file (in the parent directory), you
+should do so before proceeding.
+
+
+2) SECURITY:
+
+First, you shouldn't be afraid to run dpmaster on your machine: at the time I
+wrote those lines, only one security warning has been issued since the first
+release of dpmaster. It has always been developed with security in mind and will
+always be.
+
+Also, dpmaster needs very few things to run in its default configuration. A
+little bit of memory, a few CPU cycles from time to time and a network port are
+its only basic requirements. So feel free to restrict its privileges as much as
+you can.
+
+The UNIX/Linux version of dpmaster has even a built-in security mechanism that
+triggers when it is run with super-user (root) privileges. Basically, the
+process locks (chroots) itself in the directory "/var/empty/" and drops its
+privileges in favor of those of user "nobody". This path and this user name are
+of course customizable, thanks to the '-j' and '-u' command line options.
+
+If you are running dpmaster on a Windows system, you may want to add a
+"dpmaster" user on your computer. Make it a normal user, not a power user or an
+administrator. You'll then be able to run dpmaster using this low-privilege
+account. Right click on "dpmaster.exe" while pressing the SHIFT button; select
+"Run as...", and type "dpmaster", the password you chose for it, and your
+domain main (your computer name probably). The same result can also be achieved
+by using Windows' "runas" command.
+
+
+3) OUTPUT AND VERBOSITY LEVELS:
+
+The "-v" / "--verbose" option allows you to control the amount of text dpmaster
+outputs. Setting its verbosity to a particular level make dpmaster output all
+texts belonging to that level or below. If you don't specify a verbose level
+right after the "-v" command line option, the highest level will be used. 
+
+There are 5 verbose levels:
+   * 0: No output, except if the parsing of the command line fails.
+   * 1: Fatal errors only. It is almost similar to level 0 since fatal errors
+        mostly occur during the parsing of the command line in this version.
+   * 2: Warnings, including non-fatal system errors, malformed network messages,
+        unexpected events (when the maximum number of servers is reached for
+        instance), and the server list printed on top of log files.
+   * 3: The default level. Standard printings, describing the current activity.
+   * 4: All information (a lot!), mostly helpful when trying to debug a problem.
+
+Looking for errors in a level 4 log can be a tedious task. To make your job
+easier, all error messages in dpmaster start with the word "ERROR" in capital
+letters, and all warning messages start with the word "WARNING", again in
+capital letters.
+
+
+4) LOGGING:
+
+You can enable logging by adding "-L" or "--log" to the command line. The
+default name of the log file is "dpmaster.log", either in the working directory
+for Windows systems, or in the "/var/log" directory for UNIX systems. You can
+change the path and name of this file using the "--log-file" option. Obviously,
+the program must have write permission in the directory the log file is supposed
+to be written.
+
+The obvious way to use the log is to enable it by default. But if you intend to
+do that, you may want to consider using a lesser verbose level ("-v" or
+"--verbose", with a value of 1 - only errors, or 2 - only errors and warnings),
+as dpmaster tends to be very verbose at its default level (3) or higher.
+
+Another way to use the log is to set the verbose level to a normal or high
+value, but to enable it only when needed, and then to disable it afterwards. It
+is possible on systems that provide POSIX signals USR1 and USR2 (all supported
+systems except the Windows family). When dpmaster receives the USR1 signal, it
+opens its log file, or reopens it if it was already opened, dumps the list of
+all registered servers, and then proceeds with its normal logging. When it
+receives the USR2 signal, it closes its log file.
+
+Note that dpmaster will never overwrite an existing log file, it always appends
+logs to it. It prevents you from losing a potentially important log by mistake,
+with the drawback of having to clean the logs manually from time to time.
+
+There are a couple of pitfalls you should be aware of when using a log file:
+first, if you run dpmaster as a daemon, remember that its working directory is
+the root directory, so be careful with relative paths. And second, if you put
+your dpmaster into a chroot jail, and start or restart the log after the
+initialization phase, its path will then be rooted and relative to the jail root
+directory.
+
+
+5) GAME POLICY:
+
+If you run an instance of dpmaster, I strongly encourage you to let it open to
+any game or player. Dpmaster has been developed for this particular usage and is
+well-suited for it.
+
+That said, if you want to restrict which games are allowed on your master, you
+can use the "--game-policy" option. It makes dpmaster explicitly accept or
+reject network messages based on the game they are related to. For example:
+
+        dpmaster --game-policy accept Quake3Arena Transfusion
+
+will force dpmaster to accept servers, and answer to requests, only when they're
+related to either Q3A or Transfusion. At the opposite:
+
+        dpmaster --game-policy reject AnnoyingGame
+
+will accept any game messages except those related to AnnoyingGame.
+
+You can have multiple "--game-policy" lists on the same command line, but they
+must all use the same policy (either "accept" or "reject").
+
+As you can see in the first example, "Quake3Arena" is the name you'll have to
+use for Q3A. The other game names only depend on what code names their
+respective engines choose to advertise their servers and to make their client
+requests.
+
+Two final warnings regarding this option. First, be careful, the names are case-
+sensitive. And second, this option expects at least 2 parameters (accept/reject,
+and at least one game name), so this:
+
+        dpmaster --game-policy accept -v -n 200
+
+will make dpmaster accept messages only when they will be related to a game
+called "-v" (certainly not what you want here...).
+
+
+6) GAME PROPERTIES:
+
+Dpmaster supports 2 kinds of games: open-source games which use the DarkPlaces
+master protocol, and a few formerly closed-source games which use the Quake 3
+master protocol or a variant of it. The DarkPlaces master protocol itself is a
+variant of the Quake 3 master protocol, the main difference being that games
+send their name in addition to the usual informations or queries. That's what
+makes dpmaster able to support multiple games easily.
+
+Unfortunately, formerly closed-source games don't always send this information,
+or another information that allows dpmaster to guess the game name safely.
+That's why I call them "anonymous games" here. Up to version 2.1, the only
+anonymous game dpmaster supported was Q3A, so it was easy: if the game didn't
+send its name, it was Q3A. But starting from version 2.2, dpmaster also supports
+2 other anonymous games: RtCW and WoET. That's why a new mechanism had to be
+created to allow dpmaster to figure out which game sends it which message. This
+mechanism is called "game properties".
+
+Game properties are controlled by the command line option "--game-properties"
+(short option: "-g"). A number of properties are built into dpmaster, so you
+shouldn't have to configure anything for a standard usage. You can make it print
+its current list of game properties by using the command line option without any
+parameter. Here's the current output you get at the time I write those lines:
+
+        Game properties:
+        * et:
+           - protocols: 72, 80, 83, 84
+           - options: send-empty-servers, send-full-servers
+           - heartbeats: EnemyTerritory-1 (alive), ETFlatline-1 (dead)
+
+        * wolfmp:
+           - protocols: 50, 59, 60
+           - options: none
+           - heartbeats: Wolfenstein-1 (alive), WolfFlatline-1 (dead)
+
+        * Quake3Arena:
+           - protocols: 66, 67, 68
+           - options: none
+           - heartbeats: QuakeArena-1 (alive)
+
+"et", "wolfmp" and "Quake3Arena" are the respective game names for WoET, RtCW
+and Q3A. Each of them have been assigned several protocol numbers, options, and
+up to 2 heartbeat tags (one for alive servers, one for dying servers). All these
+values are optional: a game name can have no protocol, no option and no tag
+associated to it, although there would be no point to that.
+
+Normal (alive) heartbeat tags are used to figure out the game name when servers
+don't send it, like those of Q3A and some old Wolfenstein versions. Dead
+heartbeat tags are simply ignored, they don't trigger the sending of a "getinfo"
+message, unlike normal heartbeats.
+
+Protocol numbers are used to figure out the game name when clients don't send it
+with their "getservers" requests, and unfortunately this is the case for all the
+anonymous games currently supported. If the protocol declared by the client
+doesn't match any of the registered protocol numbers, dpmaster will use the
+first server of an anonymous game it will find, that uses this very protocol
+number, as the reference for the name. In other words, it will handle the query
+as if it has declared the same game name as this server.
+
+Options allows you to specify non-standard behaviours for a game. For example,
+the WoET's clients expect the master server to send them the complete list of
+servers, even though they don't specify that they want empty and full servers,
+like other Q3A-derived games do. By associating the proper options to its game
+name ("et"), we make sure that dpmaster will send the expected list anyway.
+The available options are: "send-empty-servers" and "send-full-servers".
+
+In order to modify the properties of a game, you have to use the command line
+option, with the game name as the first parameter, and then the modifications
+you want. You can either assign new values to a property (using "="), add values
+to it (using "+="), or remove values from it (using "-="). The values in the
+list must be separated by commas. No spaces are allowed, neither in the game
+name, nor in the list of modifications. The available properties are:
+"protocols", "options", "heartbeat" (normal heartbeat), and "flatline" (dying
+heartbeat).
+
+And you can have multiple game property changes in your command line, obviously.
+Here are a few examples.
+
+To add protocol 70 and a dead heartbeat to Q3A:
+
+        dpmaster -g Quake3Arena protocols+=70 flatline=Q3ADeadHB
+
+To remove all protocols from RtCW and give it 2 brand new ones, 4321 and 1234:
+
+        dpmaster -g wolfmp protocols=4321,1234
+
+To not send full servers to WoET clients, and to remove protocol 50 from RtCW:
+
+        dpmaster -g et options-=send-full-servers -g wolfmp protocols-=50
+
+The game properties has been added to dpmaster in order to support anonymous
+games, but it can also be useful for other games. For instance, you can force
+dpmaster to send empty servers to Warsow clients like this:
+
+        dpmaster -g Warsow options=send-empty-servers
+
+You could also specify a list of protocol numbers here, but since Warsow uses
+the DarkPlaces master protocol, both its clients and servers declares their game
+names, so it would be useless.
+
+Note that you can ask for the list of properties after you have declared some
+modifications, using a final "-g" on the command line. In this case, the printed
+list will contain your modifications. It's a good way to check that you didn't
+make any mistake before actually running your master server.
+
+
+7) FLOOD PROTECTION:
+
+If the master server you run has to handle a lot of clients, you will probably
+be interested in the flood protection mechanism Timothee Besset contributed to
+dpmaster version 2.2.
+
+Its purpose is to protect the master server bandwidth, by temporary ignoring the
+requests of clients which have already made several ones in the few seconds
+before. More precisely, a client can only make a limited number of requests (up
+to a "throttle limit") before it is ignored. The request counter associated to
+the client decreases over time though, by 1 every X seconds (X is called the
+"decay time").
+
+So for example, with a throttle limit of 5 and a decay time of 3 seconds, if a
+client does 5 requests in a row, its 4 first requests will be answered, the 5th
+one will be ignored. It will then have to wait 3 seconds for its counter to
+decrease so that one of its requests can be answered again.
+
+This protection is disabled by default because, by definition, it can disturb
+the service provided to the master's users, and given most master servers don't
+have to deal with this type of flood problem, it would be for no real benefits.
+You can enable the protection by passing the option "-f" or "--flood-protection"
+in the command line. The throttle limit and decay time can be modified with
+"--fp-throttle" and "--fp-decay-time" respectively.
+
+You also have the possibility to tune the maximum number of client records and
+the client hash size with "--max-clients" and "--cl-hash-size". But since client
+records are reused extremely rapidly in this mechanism, chances are the default
+values will be way bigger than your actual needs anyway.
+
+
+8) ADDRESS MAPPING:
+
+Address mapping allows you to tell dpmaster to transmit an IPv4 address instead
+of another one to the clients, in the "getserversResponse" messages. It can be
+useful in several cases. Imagine for instance that you have a dpmaster and a
+server behind a firewall, with local IPv4 addresses. You don't want the master
+to send the local server IP address. Instead, you probably want it to send the
+firewall address.
+
+Address mappings are currently only available for IPv4 addresses. It appears
+IPv6 doesn't need such a mechanism, since NATs have been deprecated in this new
+version of the protocol. However, feel free to contact me if you actually need
+IPv6 address mappings for some reason.
+
+Address mappings are declared on the command line, using the "-m" or "--map"
+option. You can declare as many of them as you want. The syntax is:
+
+        dpmaster -m address1=address2 -m address3=address4 ...
+
+An address can be an explicit IPv4 address, such as "192.168.1.1", or an host
+name, "www.mydomain.net" for instance. Optionally, a port number can be
+appended after a ':' (ex: "www.mydomain.net:1234").
+
+The most simple mappings are host-to-host mappings. For example:
+
+        dpmaster -m 1.2.3.4=myaddress.net
+
+In this case, each time dpmaster would have transmitted "1.2.3.4" to a client,
+it will transmit the "myaddress.net" IP address instead.
+
+If you add a port number to the first address, then the switching will only
+occur if the server matches the address and the port number.
+If you add a port number to the second address, then dpmaster will not only
+change the IP address, it will also change the port number.
+
+So there are 4 types of mappings:
+    - host1 -> host2 mappings:
+        They're simple, we just saw them.
+
+    - host1:port1 -> host2:port2 mappings:
+        If the server matches exactly the 1st address, it will be transmitted
+        as the 2nd address.
+
+    - host1:port1 -> host2 mappings:
+        If the server matches exactly the 1st address, its IP address will be
+        transmitted as the "host2" IP address. The port number won't change.
+        It's equivalent to "host1:port1=host2:port1".
+
+    - host1 -> host2:port2 mappings
+        If the server is hosted on host1, its address will be transmitted as
+        "host2:port2".
+
+Finally, be aware that you can't declare an address mapping from or to
+"0.0.0.0", neither can you declare an address mapping to a loopback address
+(i.e. 127.x.y.z:p). Mapping from a loopback address is permitted though, and
+it's actually one of the 2 only ways to make dpmaster accept a server talking
+from a loopback address (the other way being a command line option used for
+test purposes - do NOT run your master with this option!).
+
+
+9) LISTENING INTERFACES:
+
+By default, dpmaster creates one IPv4 socket and one IPv6 socket (if IPv6
+support is available of course). It will listen on every network interface, on
+the default port unless you specified another one using "-p" or "--port". If
+you want it to listen on one or more particular interface(s) instead, you will
+have to use the command line option "-l" or "--listen".
+
+Running dpmaster with no "-l" option is (almost) like running it with:
+
+        dpmaster --listen 0.0.0.0 --listen ::
+
+The first option is for listening on all IPv4 interfaces, the second for
+listening on all IPv6 interfaces, both on the default port. The only
+difference between this command line and one without any "--listen" option is
+that dpmaster will abort in the former if IPv4 or IPv6 isn't supported by your
+system, as you have explicitly requested those network sockets to be opened.
+Note that if you don't want dpmaster to listen on IPv6 interfaces, you can
+easily do it by only specifying "-l 0.0.0.0" on the command line.
+
+As usual, you can specify a port number along with an address, by appending
+":" and then the port. In this case, numeric IPv6 addresses need to be put
+between brackets first, so that dpmaster won't get confused when interpreting
+the various colons. For example:
+
+        dpmaster -l an.address.net:546 -l [2000::1234:5678]:890
+
+will make dpmaster listen on the IPv6 interface 2000::1234:5678 on port 890,
+and on the IPv4 or IPv6 interface "an.address.net" (depending on what protocol
+the resolution of this name gives) on port 546.
+
+IPv6 addressing has a few tricky aspects, and zone indices are one of them. If
+you encounter problems when configuring dpmaster for listening on a link-local
+IPv6 address, I recommend that you read the paragraph called "Link-local
+addresses and zone indices" on this Wikipedia page:
+
+        http://en.wikipedia.org/wiki/IPv6_address
+
+
+--
+Mathieu Olivier
+molivier, at users.sourceforge.net

Modified: trunk/dpmaster/doc/techinfo.txt
===================================================================
--- trunk/dpmaster/doc/techinfo.txt	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/doc/techinfo.txt	2011-07-18 21:17:24 UTC (rev 11248)
@@ -109,8 +109,8 @@
 network protocol it uses is version 5, so the clients who will join must be able
 to handle this protocol version correctly.
 
-Note that we could also have specified a number for a "gametype" (i.e. a game
-mode, like "Battle to the Death" or "Resource Harvesting"). But for this simple
+Note that we could also have specified a name or number for a "gametype" (i.e. a
+game mode, like "Battle to Death" or "Resource Harvesting"). But for this simple
 example, let's say our RTS has only one game mode.
 
 This 3-step procedure "heartbeat" -> "getinfo" -> "infoResponse" should be
@@ -147,7 +147,7 @@
 
     ftp://ftp.idsoftware.com/idstuff/quake3/docs/server.txt
 
-We have tried to keep our protocol as close as possible to Q3A's one, for a
+I have tried to keep the protocol as close as possible to Q3A's one, for a
 matter of compatibility with the numerous tools that exist for this game.
 
 Dpmaster uses 5 types of messages, plus 2 extra types for supporting IPv6, the
@@ -174,8 +174,8 @@
             The heartbeat is sent by a server when it wants to get noticed by a
             master. A server should send an heartbeat each time it becomes empty
             or full, or stop being empty or full, plus it should make sure the 
-            master gets at least one heartbeat from it every 5 to 15 minutes, so
-            the master doesn't remove it from its list of active servers.
+            master gets at least one heartbeat from it every 10 or 15 minutes,
+            so the master doesn't remove it from its list of active servers.
 
         - samples:
 

Modified: trunk/dpmaster/readme.txt
===================================================================
--- trunk/dpmaster/readme.txt	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/readme.txt	2011-07-18 21:17:24 UTC (rev 11248)
@@ -6,65 +6,56 @@
                                -------------------
 
 
- 1) INTRODUCTION
- 2) SYNTAX & OPTIONS
- 3) BASIC USAGE
- 4) SECURITY
- 5) OUTPUT AND VERBOSITY LEVELS
- 6) LOGGING
- 7) GAME POLICY
- 8) GAME PROPERTIES
- 9) FLOOD PROTECTION
-10) ADDRESS MAPPING
-11) LISTENING INTERFACES
-12) VERSION HISTORY
-13) CONTACTS & LINKS
+1) INTRODUCTION
+2) COMMAND LINE SYNTAX
+3) BASIC USAGE
+4) CONTACTS & LINKS
 
 
 1) INTRODUCTION:
 
-Dpmaster is a lightweight master server written from scratch for LordHavoc's
-game engine DarkPlaces. It is an open master server because of its free source
+Dpmaster is a lightweight master server written from scratch for DarkPlaces,
+LordHavoc's game engine. It is an open master server because of its free source
 code and documentation, and because its Quake III Arena-like protocol allows it
-to fully support new games without having to restart or reconfigure it: start
-and forget. In addition to its own protocol, dpmaster also supports the master
-protocols of "Quake III Arena" (Q3A), "Return to Castle Wolfenstein" (RtCW), and
+to fully support new games without having to restart or reconfigure it. In
+addition to its own protocol, dpmaster also supports the master protocols of
+"Quake III Arena" (Q3A), "Return to Castle Wolfenstein" (RtCW), and
 "Wolfenstein: Enemy Territory" (WoET).
 
 Several game engines currently support the DP master server protocol: DarkPlaces
 and all its derived games (such as Nexuiz and Transfusion), QFusion and most of
 its derived games (such as Warsow), and FTE QuakeWorld. Also, IOQuake3 uses it
-for its IPv6-enabled servers and clients since its version 1.36. Finally,
-dpmaster's source code has been used by a few projects as a base for creating
-their own master servers (this is the case of Tremulous, for instance).
+for its IPv6-enabled servers and clients since its version 1.36. Last but not
+least, dpmaster's source code has been used by a few projects as a base for
+creating their own master servers (this is the case of Tremulous, for instance).
 
 If you want to use the DP master protocol in one of your software, take a look
 at the section "USING DPMASTER WITH YOUR GAME" in "doc/techinfo.txt" for further
 explanations. It is pretty easy to implement, and if you ask politely, chances
 are you will be able to find someone that will let you use his running dpmaster
-if you can't get your own.
+if you can't have your own.
 
 Although dpmaster is being primarily developed on a Linux PC, it is regularly
 compiled and tested on Windows XP, OpenBSD, and Mac OS X. It has also been run
 successfully on FreeBSD, NetBSD and Windows 2000 in the past, but having no
 regular access to any of those systems, I cannot guarantee that it is still the
 case. In particular, building dpmaster on Windows 2000 may require some minor
-source code changes due to the recent addition of IPv6 support in dpmaster,
-Windows 2000 having a limited support for this protocol.
+source code changes due to the addition of IPv6 support in dpmaster, Windows
+2000 having a limited support for this protocol.
 
 Take a look at the "COMPILING DPMASTER" section in "doc/techinfo.txt" for more
 practical information on how to build it.
 
 The source code of dpmaster is available under the GNU General Public License,
-version 2. You can find the text of this license in the file "doc/license.txt".
+version 2. The complete text of this license is in the file "doc/license.txt".
 
 
-2) SYNTAX & OPTIONS:
+2) COMMAND LINE SYNTAX:
 
 The syntax of the command line is the classic: "dpmaster [options]". Running
 "dpmaster -h" will print the available options for your version. Be aware that
 some options are only available on UNIXes, including all security-related
-options - see the "SECURITY" section below.
+options - see the "SECURITY" section in "doc/manual.txt".
 
 All options have a long name (a string), and most of them also have a short name
 (one character). In the command line, long option names are preceded by 2
@@ -90,7 +81,7 @@
 should work perfectly. Being an open master server, it does not require any
 game-related configuration. The vast majority of dpmaster's options deal with
 how you want to run it: which network interfaces to use, how many servers it
-will accept, where to put the log file .... and all those options have default
+will accept, where to put the log file, etc. And all those options have default
 values that should suit almost everyone.
 
 That being said, here are a few options you may find handy.
@@ -98,482 +89,19 @@
 The most commonly used one is probably "-D" (or "--daemon"), a UNIX-specific
 option to make the program run in the background, as a daemon process.
 
-If you intent to run dpmaster for a long period of time, you may want to take a
-look at the log-related options before starting it (see the LOGGING section). In
-particular, make sure you have write permission in the directory the log file is
-supposed to be written.
+You can also use the classic verbose option "-v" to make dpmaster print extra
+information (see "OUTPUT AND VERBOSITY LEVELS" in "doc/manual.txt").
 
-Finally, you can use the classic verbose option "-v" to make dpmaster print
-extra information (see "OUTPUT AND VERBOSITY LEVELS" below for more).
+Finally, if you intent to run dpmaster for a long period of time, you may want
+to take a look at the log-related options before starting it (see the LOGGING
+section in "doc/manual.txt").
 
+More options and their descriptions can be found in "doc/manual.txt", so feel
+free to read this file if you have specific needs.
 
-4) SECURITY:
 
-First, you shouldn't be afraid to run dpmaster on your machine: at the time I
-wrote those lines, only one security warning has been issued since the first
-release of dpmaster. It has always been developed with security in mind and will
-always be.
+4) CONTACTS & LINKS:
 
-Also, dpmaster needs very few things to run in its default configuration. A
-little bit of memory, a few CPU cycles from time to time and a network port are
-its only basic requirements. So feel free to restrict its privileges as much as
-you can.
-
-The UNIX/Linux version of dpmaster has even a builtin security mechanism that
-triggers when it is run with super-user (root) privileges. Basically, the
-process locks (chroots) itself in the directory "/var/empty/" and drops its
-privileges in favor of those of user "nobody". This path and this user name are
-of course customizable, thanks to the '-j' and '-u' command line options.
-
-If you are running dpmaster on a Windows system, you may want to add a
-"dpmaster" user on your computer. Make it a normal user, not a power user or an
-administrator. You'll then be able to run dpmaster using this low-privilege
-account. Right click on "dpmaster.exe" while pressing the SHIFT button; select
-"Run as...", and type "dpmaster", the password you chose for it, and your
-domain main (your computer name probably). The same result can also be achieved
-by using Windows' "runas" command.
-
-
-5) OUTPUT AND VERBOSITY LEVELS:
-
-The "-v" / "--verbose" option allows you to control the amount of text dpmaster
-outputs. Setting its verbosity to a particular level make dpmaster output all
-texts belonging to that level or below. If you don't specify a verbose level
-right after the "-v" command line option, the highest level will be used. 
-
-There are 5 verbose levels:
-   * 0: No output, except if the parsing of the command line fails.
-   * 1: Fatal errors only. It is almost similar to level 0 since fatal errors
-        mostly occur during the parsing of the command line in this version.
-   * 2: Warnings, including non-fatal system errors, malformed network messages,
-        unexpected events (when the maximum number of servers is reached for
-        instance), and the server list printed on top of log files.
-   * 3: The default level. Standard printings, describing the current activity.
-   * 4: All information (a lot!), mostly helpful when trying to debug a problem.
-
-Looking for errors in a level 4 log can be a tedious task. To make your job
-easier, all error messages in dpmaster start with the word "ERROR" in capital
-letters, and all warning messages start with the word "WARNING", again in
-capital letters.
-
-
-6) LOGGING:
-
-You can enable logging by adding "-L" or "--log" to the command line. The
-default name of the log file is "dpmaster.log", either in the working directory
-for Windows systems, or in the "/var/log" directory for UNIX systems. You can
-change the path and name of this file using the "--log-file" option.
-
-The obvious way to use the log is to enable it by default. But if you want to do
-that, you may want to consider using a lesser verbose level ("-v" or
-"--verbose", with a value of 1 - only errors, or 2 - only errors and warnings),
-as dpmaster tends to be very verbose at its default level (3) or higher.
-
-Another way to use the log is to set the verbose level to its maximum value, but
-to enable the log only when needed, and then to disable it afterwards. This is
-possible on systems that provide POSIX signals USR1 and USR2 (all supported
-systems except the Windows family). When dpmaster receives the USR1 signal, it
-opens its log file, or reopens it if it was already opened, dumps the list of
-all registered servers, and then proceeds with its normal logging. When it
-receives the USR2 signal, it closes its log file.
-
-Note that dpmaster will never overwrite an existing log file, it always appends
-logs to it. It prevents you from losing a potentially important log by mistake,
-with the drawback of having to clean the logs manually from time to time.
-
-There are a couple of pitfalls you should be aware of when using a log file:
-first, if you run dpmaster as a daemon, remember that its working directory is
-the root directory, so be careful with relative paths. And second, if you put
-your dpmaster into a chroot jail, and start or restart the log after the
-initialization phase, its path will then be rooted and relative to the jail root
-directory.
-
-
-7) GAME POLICY:
-
-If you run an instance of dpmaster, we strongly encourage you to let it open to
-any game or player. Dpmaster has been developed for this particular usage and is
-well-suited for it.
-
-That said, if you want to restrict which games are allowed on your master, you
-can use the "--game-policy" option. It makes dpmaster explicitly accept or
-reject network messages based on the game they are related to. For example:
-
-        dpmaster --game-policy accept Quake3Arena Transfusion
-
-will force dpmaster to accept servers, and answer to requests, only when they're
-related to either Q3A or Transfusion. At the opposite:
-
-        dpmaster --game-policy reject AnnoyingGame
-
-will accept any game messages except those related to AnnoyingGame.
-
-You can have multiple "--game-policy" lists on the same command line, but they
-must all use the same policy (either "accept" or "reject").
-
-As you can see in the first example, "Quake3Arena" is the name you'll have to
-use for Q3A. The other game names only depend on what code names their
-respective engines choose to advertise their servers and to make their client
-requests.
-
-Two final warnings regarding this option. First, be careful, the names are case-
-sensitive. And second, this option expects at least 2 parameters (accept/reject,
-and at least one game name), so this:
-
-        dpmaster --game-policy accept -v -n 200
-
-will make dpmaster accept messages only when they will be related to a game
-called "-v" (certainly not what you want...).
-
-
-8) GAME PROPERTIES:
-
-Dpmaster supports 2 kinds of games: open-source games which use the DarkPlaces
-master protocol, and a few formerly closed-source games which use the Quake 3
-master protocol or a variant of it. The DarkPlaces master protocol itself is a
-variant of the Quake 3 master protocol, the main difference being that games
-send their name in addition to the usual informations or queries. That's what
-makes dpmaster able to support multiple games easily.
-
-Unfortunately, formerly closed-source games don't always send this information,
-or another information that allows dpmaster to guess the game name safely.
-That's why we call them "anonymous games" here. Up to version 2.1, the only
-anonymous game dpmaster supported was Q3A, so it was easy: if the game didn't
-send its name, it was Q3A. But starting from version 2.2, dpmaster also supports
-2 other anonymous games: RtCW and WoET. That's why a new mechanism had to be
-created to allow dpmaster to figure out which game sends it which message. This
-mechanism is called "game properties".
-
-Game properties are controlled by the command line option "--game-properties"
-(short option: "-g"). A number of properties are built into dpmaster, so you
-shouldn't have to configure anything for a standard usage. You can make it print
-its current list of game properties by using the command line option without any
-parameter. Here's the current output you get at the time I write those lines:
-
-        Game properties:
-        * et:
-           - protocols: 72, 80, 83, 84
-           - options: send-empty-servers, send-full-servers
-           - heartbeats: EnemyTerritory-1 (alive), ETFlatline-1 (dead)
-
-        * wolfmp:
-           - protocols: 50, 59, 60
-           - options: none
-           - heartbeats: Wolfenstein-1 (alive), WolfFlatline-1 (dead)
-
-        * Quake3Arena:
-           - protocols: 66, 67, 68
-           - options: none
-           - heartbeats: QuakeArena-1 (alive)
-
-"et", "wolfmp" and "Quake3Arena" are the respective game names for WoET, RtCW
-and Q3A. Each of them have been assigned several protocol numbers, options, and
-up to 2 heartbeat tags (one for alive servers, one for dying servers). All these
-values are optional: a game name can have no protocol, no option and no tag
-associated to it, although there would be no point to that.
-
-Normal (alive) heartbeat tags are used to figure out the game name when servers
-don't send it, like those of Q3A and some old Wolfenstein versions. Dead
-heartbeat tags are simply ignored, they don't trigger the sending of a "getinfo"
-message, unlike normal heartbeats.
-
-Protocol numbers are used to figure out the game name when clients don't send it
-with their "getservers" requests, and unfortunately this is the case for all the
-anonymous games currently supported. If the protocol declared by the client
-doesn't match any of the registered protocol numbers, dpmaster will use the
-first server of an anonymous game it will find, that uses this very protocol
-number, as the reference for the name. In other words, it will handle the query
-as if it has declared the same game name as this server.
-
-Options allows you to specify non-standard behaviours for a game. For example,
-the WoET's clients expect the master server to send them the complete list of
-servers, even though they don't specify that they want empty and full servers,
-like other Q3A-derived games do. By associating the proper options to its game
-name ("et"), we make sure that dpmaster will send the expected list anyway.
-The available options are: "send-empty-servers" and "send-full-servers".
-
-In order to modify the properties of a game, you have to use the command line
-option, with the game name as the first parameter, and then the modifications
-you want. You can either assign new values to a property (using "="), add values
-to it (using "+="), or remove values from it (using "-="). The values in the
-list must be separated by commas. No spaces are allowed, neither in the game
-name, nor in the list of modifications. The available properties are:
-"protocols", "options", "heartbeat" (normal heartbeat), and "flatline" (dying
-heartbeat).
-
-And you can have multiple game property changes in your command line, obviously.
-Here are a few examples.
-
-To add protocol 70 and a dead heartbeat to Q3A:
-
-        dpmaster -g Quake3Arena protocols+=70 flatline=Q3ADeadHB
-
-To remove all protocols from RtCW and give it 2 brand new ones, 4321 and 1234:
-
-        dpmaster -g wolfmp protocols=4321,1234
-
-To not send full servers to WoET clients, and to remove protocol 50 from RtCW:
-
-        dpmaster -g et options-=send-full-servers -g wolfmp protocols-=50
-
-The game properties has been added to dpmaster in order to support anonymous
-games, but it can also be useful for other games. For instance, you can force
-dpmaster to send empty servers to Warsow clients like this:
-
-        dpmaster -g Warsow options=send-empty-servers
-
-You could also specify a list of protocol numbers here, but since Warsow uses
-the DarkPlaces master protocol, both its clients and servers declares their game
-names, so it would be useless.
-
-Note that you can ask for the list of properties after you have declared some
-modifications, using a final "-g" on the command line. In this case, the printed
-list will contain your modifications. It's a good way to check that you didn't
-make any mistake before actually running your master server.
-
-
-9) FLOOD PROTECTION:
-
-If the master server you run has to handle a lot of clients, you will probably
-be interested in the flood protection mechanism Timothee Besset contributed to
-dpmaster version 2.2.
-
-Its purpose is to protect the master server bandwidth, by temporary ignoring the
-requests of clients which have already made several ones in the few seconds
-before. More precisely, a client can only make a limited number of requests (up
-to a "throttle limit") before it is only allowed one request every X seconds (X
-is called the "decay time"). A simple way to view it is to imagine that each
-client has initially - and at most - a number of tokens equal to the throttle
-limit minus 1. It must use/give one token for each request he does, but it
-regains tokens over time, 1 token every 3 seconds for instance if the decay time
-is set to 3. So for example, with a throttle limit of 5 and a decay time of 3,
-a client could do 5 - 1 = 4 requests in a row before having to wait 3 seconds
-between its requests, or they will not be answered.
-
-This protection is disabled by default because, by definition, it can disturb
-the service provided to the master's users, and given most master servers don't
-have to deal with this type of flood problem, it would be for no real benefits.
-You can enable the protection by passing the option "-f" or "--flood-protection"
-in the command line. The throttle limit and decay time can be modified with
-"--fp-throttle" and "--fp-decay-time" respectively.
-
-You also have the possibility to tune the maximum number of client records and
-the client hash size with "--max-clients" and "--cl-hash-size". But since client
-records are reused extremely rapidly in this mechanism, chances are the default
-values will be way bigger than your actual needs anyway.
-
-
-10) ADDRESS MAPPING:
-
-Address mapping allows you to tell dpmaster to transmit an IPv4 address instead
-of another one to the clients, in the "getserversResponse" messages. It can be
-useful in several cases. Imagine for instance that you have a dpmaster and a
-server behind a firewall, with local IPv4 addresses. You don't want the master
-to send the local server IP address. Instead, you probably want it to send the
-firewall address.
-
-Address mappings are currently only available for IPv4 addresses. It appears
-IPv6 doesn't need such a mechanism, since NATs have been deprecated in this new
-version of the protocol. However, feel free to contact me if you actually need
-IPv6 address mappings for some reason.
-
-Address mappings are declared on the command line, using the "-m" or "--map"
-option. You can declare as many of them as you want. The syntax is:
-
-        dpmaster -m address1=address2 -m address3=address4 ...
-
-An address can be an explicit IPv4 address, such as "192.168.1.1", or an host
-name, "www.mydomain.net" for instance. Optionally, a port number can be
-appended after a ':' (ex: "www.mydomain.net:1234").
-
-The most simple mappings are host-to-host mappings. For example:
-
-        dpmaster -m 1.2.3.4=myaddress.net
-
-In this case, each time dpmaster would have transmitted "1.2.3.4" to a client,
-it will transmit the "myaddress.net" IP address instead.
-
-If you add a port number to the first address, then the switching will only
-occur if the server matches the address and the port number.
-If you add a port number to the second address, then dpmaster will not only
-change the IP address, it will also change the port number.
-
-So there are 4 types of mappings:
-    - host1 -> host2 mappings:
-        They're simple, we just saw them.
-
-    - host1:port1 -> host2:port2 mappings:
-        If the server matches exactly the 1st address, it will be transmitted
-        as the 2nd address.
-
-    - host1:port1 -> host2 mappings:
-        If the server matches exactly the 1st address, its IP address will be
-        transmitted as the "host2" IP address. The port number won't change.
-        It's equivalent to "host1:port1=host2:port1".
-
-    - host1 -> host2:port2 mappings
-        If the server is hosted on host1, its address will be transmitted as
-        "host2:port2".
-
-Finally, be aware that you can't declare an address mapping from or to
-"0.0.0.0", neither can you declare an address mapping to a loopback address
-(i.e. 127.x.y.z:p). Mapping from a loopback address is permitted though, and
-it's actually one of the 2 only ways to make dpmaster accept a server talking
-from a loopback address (the other way being a command line option used for
-test purposes - do NOT run your master with this option!).
-
-
-11) LISTENING INTERFACES:
-
-By default, dpmaster creates one IPv4 socket and one IPv6 socket (if IPv6
-support is available of course). It will listen on every network interface, on
-the default port unless you specified another one using "-p" or "--port". If
-you want it to listen on one or more particular interface(s) instead, you will
-have to use the command line option "-l" or "--listen".
-
-Running dpmaster with no "-l" option is (almost) like running it with:
-
-        dpmaster --listen 0.0.0.0 --listen ::
-
-The first option is for listening on all IPv4 interfaces, the second for
-listening on all IPv6 interfaces, both on the default port. The only
-difference between this command line and one without any "--listen" option is
-that dpmaster will abort in the former if IPv4 or IPv6 isn't supported by your
-system, as you have explicitly requested those network sockets to be opened.
-Note that if you don't want dpmaster to listen on IPv6 interfaces, you can
-easily do it by only specifying "-l 0.0.0.0" on the command line.
-
-As usual, you can specify a port number along with an address, by appending
-":" and then the port. In this case, numeric IPv6 addresses need to be put
-between brackets first, so that dpmaster won't get confused when interpreting
-the various colons. For example:
-
-        dpmaster -l an.address.net:546 -l [2000::1234:5678]:890
-
-will make dpmaster listen on the IPv6 interface 2000::1234:5678 on port 890,
-and on the IPv4 or IPv6 interface "an.address.net" (depending on what protocol
-the resolution of this name gives) on port 546.
-
-IPv6 addressing has a few tricky aspects, and zone indices are one of them. If
-you encounter problems when configuring dpmaster for listening on a link-local
-IPv6 address, I recommend that you read the paragraph called "Link-local
-addresses and zone indices" on this Wikipedia page:
-
-        http://en.wikipedia.org/wiki/IPv6_address
-
-
-12) VERSION HISTORY:
-
-    - version 2.2-dev:
-        Flood protection against abusive client requests, by Timothee Besset
-        New system for managing game properties (see GAME PROPERTIES above)
-        Support for RtCW and WoET, using the game properties
-        Shutdown heartbeats and unknown heartbeats are now ignored
-        The chroot jail was preventing daemonization (fixed thanks to LordHavoc)
-        The game type was incorrect when printing the server list in the log
-        Less debug output when building a getserversResponse in verbose mode
-
-    - version 2.1:
-        A gametype value can now be any string, not just a number
-
-    - version 2.0:
-        Gametype filter support in the server list queries (see techinfo.txt)
-        New option "--game-policy" to filter games (see GAME POLICY above)
-        IPv6 support, including 2 new messages types (see techinfo.txt)
-        Logging support (see LOGGING above)
-        Only the last packet of a getservers response gets an EOT mark now
-        The default number of servers is now 4096
-        Improved listening interface option (see LISTENING INTERFACES above)
-        Long format for all command line options (see SYNTAX & OPTIONS above)
-        The server lists are now sent in a semi-random order, for fairness
-        The new hash function supports up to 16-bit hashes
-        The default hash size has been increased to 10 bits
-        0 is no longer an invalid hash size
-        New option "--allow-loopback", for debugging purposes only!
-        New option "--hash-ports", for debugging purposes only!
-        Various updates and improvements in the documentation
-        No warning is printed anymore if a server changes its game name
-        No longer tolerates several mapping declarations for the same address
-        A lot of minor changes and fixes in the code
-        The test suite now requires the Socket6 Perl module to run
-
-    - version 1.7:
-        There's now a maximum number of servers per IP address (default: 32)
-        New option to set the maximum number of servers per IP address (-N)
-        The maximum number of servers recorded by default is now 1024
-        The default hash size has been increased from 6 bits to 8 bits
-        A few Perl scripts have been added to provide basic automated testing
-        A rare bug where a server was occasionally skipped was fixed
-        The compilation with MS Visual Studio 2005 is fixed
-        Protocol numbers less than or equal to 0 are now handled correctly
-        Servers can no longer keep their slots without sending infoResponses
-        Games having a name starting with a number are now handled correctly
-        A few minor memory leaks were removed in the address mapping init code
-        Additional checks of the command line options and the messages syntax
-        The requirement of a "clients" value in infoResponses is now enforced
-        The "infoResponse" description in techinfo.txt has been corrected
-        The "heartbeat" description in techinfo.txt has been corrected
-        The time is now printed to the console each time a packet is received
-        Made it clear in the doc that any game can be supported out of the box
-
-    - version 1.6:
-        Several getserversResponse may now be sent for a single getservers
-        A getserversResponse packet can no longer exceed 1400 bytes
-        The maximum number of servers recorded by default has doubled (now 256)
-        The default hash size has been increased from 5 bits to 6 bits
-        Several updates and corrections in the documentation
-
-    - version 1.5.1:
-        Compilation on FreeBSD was fixed
-        A couple of minor changes in "COMPILING DPMASTER" (in techinfo.txt)
-
-    - version 1.5:
-        Address mapping added (see ADDRESS MAPPING above)
-        Servers on a loopback address are accepted again if they have a mapping
-        A valid "infoReponse" is now rejected if its challenge has timed out
-        The size of the challenge sent with "getinfo" has been made random
-        A timed-out server is now removed as soon as a new server needs a slot
-        Several little changes in the printings to make them more informative
-        A technical documentation was added
-        Compiling dpmaster with MSVC works again
-
-    - version 1.4:
-        Dpmaster now quits if it can't chroot, switch privileges or daemonize
-        Packets coming from a loopback address are now rejected with a warning
-        Listen address option added (-l)
-        Modified Makefile to please BSD make
-
-    - version 1.3.1:
-        SECURITY WARNING: 2 exploitable buffer overflows were fixed
-        Verbose option parsing fixed
-        Paranoid buffer overflow checkings added, in case of future code changes
-
-    - version 1.3:
-        Ability to support any game which uses DP master protocol (ex: QFusion)
-
-    - version 1.2.1:
-        A major bug was fixed (a NULL pointer dereference introduced in v1.2)
-
-    - version 1.2:
-        A major bug was fixed (an infinite loop in HandleGetServers)
-
-    - version 1.1:
-        A lot of optimizations and tweakings
-        Verbose option added (-v)
-        Hash size option added (-H)
-        Daemonization option added on UNIXes (-D)
-        Chrooting and privileges dropping when running as root added on UNIXes
-        MinGW cross-compilation support added
-
-    - version 1.01:
-        A major bug was fixed. Most of the servers weren't sent to the clients
-
-    - version 1.0 :
-        First publicly available version
-
-
-13) CONTACTS & LINKS:
-
 You can get the latest versions of DarkPlaces and dpmaster on the DarkPlaces
 home page <http://icculus.org/twilight/darkplaces/>.
 

Modified: trunk/dpmaster/src/clients.c
===================================================================
--- trunk/dpmaster/src/clients.c	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/clients.c	2011-07-18 21:17:24 UTC (rev 11248)
@@ -4,7 +4,7 @@
 	Client list and flood protection for dpmaster
 
 	Copyright (C) 2010  Timothee Besset
-	Copyright (C) 2010  Mathieu Olivier
+	Copyright (C) 2010-2011  Mathieu Olivier
 
 	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
@@ -42,8 +42,7 @@
 static client_t* clients = NULL;
 
 static unsigned int max_nb_clients = DEFAULT_MAX_NB_CLIENTS;
-static user_hash_table_t hash_clients_ipv4;
-static user_hash_table_t hash_clients_ipv6;
+static user_hash_table_t hash_clients;
 static size_t cl_hash_size = DEFAULT_CL_HASH_SIZE;
 
 // rolling window for allocation
@@ -86,7 +85,7 @@
 Add a client to an hash table
 ====================
 */
-static qboolean Cl_AddClient( user_hash_table_t *hash_clients, const struct sockaddr_storage *address, socklen_t addrlen )
+static qboolean Cl_AddClient( const struct sockaddr_storage *address, socklen_t addrlen )
 {
 	int first_slot = ( last_used_slot + 1 ) % max_nb_clients;
 	int free_slot = first_slot;
@@ -133,7 +132,7 @@
 		free_client->last_time = crt_time;
 
 		hash = Com_AddressHash( address, cl_hash_size );
-		Com_UserHashTable_Add( hash_clients, &free_client->user, hash );
+		Com_UserHashTable_Add( &hash_clients, &free_client->user, hash );
 
 		Com_Printf( MSG_DEBUG,
 					"> New client added: %s\n"
@@ -199,8 +198,8 @@
 */
 qboolean Cl_SetFPDecayTime (time_t decay)
 {
-	// Too late? Or too small?
-	if (clients != NULL || decay <= 0)
+	// Too small?
+	if (decay <= 0)
 		return false;
 
 	fp_decay_time = decay;
@@ -217,8 +216,8 @@
 */
 qboolean Cl_SetFPThrottle (unsigned int throttle)
 {
-	// Too late? Or too small?
-	if (clients != NULL || throttle <= 1)
+	// Too small?
+	if (throttle <= 1)
 		return false;
 
 	fp_throttle = throttle;
@@ -256,7 +255,7 @@
 
 		Com_Printf( MSG_NORMAL, "> %u client records allocated\n", max_nb_clients );
 
-		if (! Com_UserHashTable_InitTables (&hash_clients_ipv4, &hash_clients_ipv6, cl_hash_size, "Client"))
+		if (! Com_UserHashTable_Init (&hash_clients, cl_hash_size, "client"))
 			return false;
 	}
 	
@@ -273,7 +272,6 @@
 */
 qboolean Cl_BlockedByThrottle( const struct sockaddr_storage* addr, socklen_t addrlen )
 {
-	user_hash_table_t* hash_clients;
 	unsigned int hash;
 	client_t *client;
 	qboolean (*IsSameAddress) (const struct sockaddr_storage* addr1, const struct sockaddr_storage* addr2, qboolean* same_public_address);
@@ -283,20 +281,16 @@
 		return false;
 
 	if ( addr->ss_family == AF_INET6 )
-	{
-		hash_clients = &hash_clients_ipv6;
 		IsSameAddress = &Com_SameIPv6Addr;
-	}
 	else
 	{
 		assert (addr->ss_family == AF_INET);
-		hash_clients = &hash_clients_ipv4;
 		IsSameAddress = &Com_SameIPv4Addr;
 	}
 
 	// look for activity information about this client
 	hash = Com_AddressHash( addr, cl_hash_size );
-	client = (client_t*)hash_clients->entries[ hash ];
+	client = (client_t*)hash_clients.entries[ hash ];
 	while ( client != NULL )
 	{
 		if ( addr->ss_family == client->user.address.ss_family )
@@ -308,25 +302,27 @@
 			// found entry
 			if ( same_public_address )
 			{
-				int count = Cl_QueryThrottleDecay( client );
-				if ( count >= fp_throttle )
+				msg_level_t msg_level;
+				const char* msg_result;
+
+				int new_count = Cl_QueryThrottleDecay( client ) + 1;
+				qboolean is_blocked = ( new_count >= fp_throttle );
+				if ( ! is_blocked )
 				{
-					Com_Printf( MSG_NORMAL, "> Client %s: throttled (count == %d)\n", peer_address, count );
-					return true;
-				}
+					client->count = new_count;
+					client->last_time = crt_time;
+					msg_level = MSG_DEBUG;
+					msg_result = "not throttled";
 
-				count++;
-				client->count = count;
-				client->last_time = crt_time;
-
-				if ( count >= fp_throttle )
+				}
+				else
 				{
-					Com_Printf( MSG_NORMAL, "> Client %s: start throttling (count == %d)\n", peer_address, count );
-					return true;
+					msg_level = MSG_NORMAL;
+					msg_result = "throttled";
 				}
 
-				Com_Printf( MSG_DEBUG, "> Client %s: not throttled (count == %d)\n", peer_address, count );
-				return false;
+				Com_Printf( msg_level, "> Client %s: %s (new count == %d)\n", peer_address, msg_result, new_count );
+				return is_blocked;
 			}
 		}
 
@@ -334,5 +330,5 @@
 	}
 
 	assert( client == NULL );
-	return ( ! Cl_AddClient( hash_clients, addr, addrlen ) );
+	return ( ! Cl_AddClient( addr, addrlen ) );
 }

Modified: trunk/dpmaster/src/common.c
===================================================================
--- trunk/dpmaster/src/common.c	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/common.c	2011-07-18 21:17:24 UTC (rev 11248)
@@ -4,7 +4,7 @@
 
 	Utility functions for dpmaster
 
-	Copyright (C) 2008-2009  Mathieu Olivier
+	Copyright (C) 2008-2011  Mathieu Olivier
 
 	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
@@ -215,7 +215,7 @@
 }
 
 
-// ---------- Private functions (user hash table) ---------- //
+// ---------- Public functions (user hash table) ---------- //
 
 /*
 ====================
@@ -224,54 +224,33 @@
 Initialize a user hash table
 ====================
 */
-static qboolean Com_UserHashTable_Init (user_hash_table_t* table,
-										size_t hash_size,
-										const char* table_name,
-										sa_family_t addr_family,
-										const char* proto_name)
+qboolean Com_UserHashTable_Init (user_hash_table_t* table,
+								 size_t hash_size,
+								 const char* table_name)
 {
-	if (Sys_IsListeningOn (addr_family))
-	{
-		size_t array_size = (1 << hash_size) * sizeof (user_t*);
-		user_t** result;
+	size_t array_size;
+	user_t** result;
 
-		result = malloc (array_size);
-		if (result == NULL)
-		{
-			Com_Printf (MSG_ERROR,
-						"> ERROR: can't allocate the %s %s hash table (%s)\n",
-						table_name, proto_name, strerror (errno));
-			return false;
-		}
+	assert (table_name[0] != '\0');
 
-		memset (result, 0, array_size);
-		table->entries = result;
-
-		Com_Printf (MSG_DEBUG,
-					"> %s hash table allocated for %s (%u entries)\n",
-					table_name, proto_name, 1 << hash_size);
+	array_size = (1 << hash_size) * sizeof (user_t*);
+	result = malloc (array_size);
+	if (result == NULL)
+	{
+		Com_Printf (MSG_ERROR,
+					"> ERROR: can't allocate the %s hash table (%s)\n",
+					table_name, strerror (errno));
+		return false;
 	}
 
-	return true;
-}
+	memset (result, 0, array_size);
+	table->entries = result;
 
+	Com_Printf (MSG_DEBUG,
+				"> %c%s hash table allocated (%u entries)\n",
+				toupper (table_name[0]), &table_name[1], 1 << hash_size);
 
-// ---------- Public functions (user hash table) ---------- //
-
-/*
-====================
-Com_UserHashTable_InitTables
-
-Initialize user hash tables
-====================
-*/
-qboolean Com_UserHashTable_InitTables (user_hash_table_t* ipv4_table,
-									   user_hash_table_t* ipv6_table,
-									   size_t hash_size,
-									   const char* tables_name)
-{
-	return (Com_UserHashTable_Init (ipv4_table, hash_size, tables_name, AF_INET, "IPv4") &&
-			Com_UserHashTable_Init (ipv6_table, hash_size, tables_name, AF_INET6, "IPv6"));
+	return true;
 }
 
 

Modified: trunk/dpmaster/src/common.h
===================================================================
--- trunk/dpmaster/src/common.h	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/common.h	2011-07-18 21:17:24 UTC (rev 11248)
@@ -3,7 +3,7 @@
 
 	Common header file for dpmaster
 
-	Copyright (C) 2004-2010  Mathieu Olivier
+	Copyright (C) 2004-2011  Mathieu Olivier
 
 	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
@@ -26,6 +26,7 @@
 
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -140,11 +141,10 @@
 
 // ---------- Public functions (user hash table) ---------- //
 
-// Initialize user hash tables
-qboolean Com_UserHashTable_InitTables (user_hash_table_t* ipv4_table,
-									   user_hash_table_t* ipv6_table,
-									   size_t hash_size,
-									   const char* tables_name);
+// Initialize a user hash table
+qboolean Com_UserHashTable_Init (user_hash_table_t* table,
+								 size_t hash_size,
+								 const char* table_name);
 
 // Add a user to the hash table
 void Com_UserHashTable_Add (user_hash_table_t* table, user_t* user, unsigned int hash);

Modified: trunk/dpmaster/src/dpmaster.c
===================================================================
--- trunk/dpmaster/src/dpmaster.c	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/dpmaster.c	2011-07-18 21:17:24 UTC (rev 11248)
@@ -76,8 +76,8 @@
 		"Set the decay time of the flood protection, in seconds (default: %d)",
 		{ DEFAULT_FP_DECAY_TIME, 0 },
 		'\0',
-		0,
-		0
+		1,
+		1
 	},
 	{
 		"fp-throttle",
@@ -85,8 +85,8 @@
 		"Set the throttle limit of the flood protection (default: %d)",
 		{ DEFAULT_FP_THROTTLE, 0 },
 		'\0',
-		0,
-		0
+		1,
+		1
 	},
 	{
 		"game-properties",

Modified: trunk/dpmaster/src/servers.c
===================================================================
--- trunk/dpmaster/src/servers.c	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/servers.c	2011-07-18 21:17:24 UTC (rev 11248)
@@ -3,7 +3,7 @@
 
 	Server list and address mapping management for dpmaster
 
-	Copyright (C) 2004-2009  Mathieu Olivier
+	Copyright (C) 2004-2011  Mathieu Olivier
 
 	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
@@ -40,8 +40,7 @@
 static server_t* servers = NULL;
 static unsigned int max_nb_servers = DEFAULT_MAX_NB_SERVERS;
 static unsigned int nb_servers = 0;
-static user_hash_table_t hash_table_ipv4;
-static user_hash_table_t hash_table_ipv6;
+static user_hash_table_t hash_table;
 static size_t sv_hash_size = DEFAULT_SV_HASH_SIZE;
 
 static unsigned int max_per_address = DEFAULT_MAX_NB_SERVERS_PER_ADDRESS;
@@ -154,22 +153,17 @@
 static server_t* Sv_GetByAddr_Internal (const struct sockaddr_storage* address, unsigned int* same_address_found)
 {
 	unsigned int hash = Com_AddressHash (address, sv_hash_size);
-	user_hash_table_t* hash_table;
 	server_t* sv;
 	qboolean (*IsSameAddress) (const struct sockaddr_storage* addr1, const struct sockaddr_storage* addr2, qboolean* same_public_address);
 	
 	if (address->ss_family == AF_INET6)
-	{
-		hash_table = &hash_table_ipv6;
 		IsSameAddress = &Com_SameIPv6Addr;
-	}
 	else
 	{
 		assert (address->ss_family == AF_INET);
-		hash_table = &hash_table_ipv4;
 		IsSameAddress = &Com_SameIPv4Addr;
 	}
-	sv = (server_t*)hash_table->entries[hash];
+	sv = (server_t*)hash_table.entries[hash];
 
 	*same_address_found = 0;
 	while (sv != NULL)
@@ -179,22 +173,26 @@
 
 		if (Sv_IsActive (sv_ind))
 		{
-			// Same address?
-			qboolean same_public_address;
-			qboolean same_address;
-
-			same_public_address = false;
-			same_address = IsSameAddress (&sv->user.address, address, &same_public_address);
-			if (same_public_address)
-				*same_address_found += 1;
-			if (same_address)
+			const struct sockaddr_storage* sv_address = &sv->user.address;
+			if (address->ss_family == sv_address->ss_family)
 			{
-				// Move it on top of the list (it's useful because heartbeats
-				// are almost always followed by infoResponses)
-				Com_UserHashTable_Remove (&sv->user);
-				Com_UserHashTable_Add (hash_table, &sv->user, hash);
+				// Same address?
+				qboolean same_public_address;
+				qboolean same_address;
 
-				return sv;
+				same_public_address = false;
+				same_address = IsSameAddress (sv_address, address, &same_public_address);
+				if (same_public_address)
+					*same_address_found += 1;
+				if (same_address)
+				{
+					// Move it on top of the list (it's useful because heartbeats
+					// are almost always followed by infoResponses)
+					Com_UserHashTable_Remove (&sv->user);
+					Com_UserHashTable_Add (&hash_table, &sv->user, hash);
+
+					return sv;
+				}
 			}
 		}
 		
@@ -508,7 +506,7 @@
 	else
 		Com_Printf (MSG_NORMAL, "%u)\n", max_per_address);
 
-	if (! Com_UserHashTable_InitTables (&hash_table_ipv4, &hash_table_ipv6, sv_hash_size, "Server"))
+	if (! Com_UserHashTable_Init (&hash_table, sv_hash_size, "server"))
 		return false;
 
 	return true;
@@ -529,7 +527,6 @@
 	const addrmap_t* addrmap = NULL;
 	unsigned int hash;
 	unsigned int ind;
-	user_hash_table_t* hash_table;
 
 	sv = Sv_GetByAddr_Internal (address, &nb_same_address);
 	if (sv != NULL)
@@ -631,11 +628,7 @@
 
 	// Add it to the list it belongs to
 	hash = Com_AddressHash (address, sv_hash_size);
-	if (address->ss_family == AF_INET6)
-		hash_table = &hash_table_ipv6;
-	else
-		hash_table = &hash_table_ipv4;
-	Com_UserHashTable_Add (hash_table, &sv->user, hash);
+	Com_UserHashTable_Add (&hash_table, &sv->user, hash);
 
 	sv->state = sv_state_uninitialized;
 	sv->timeout = crt_time + TIMEOUT_HEARTBEAT;

Modified: trunk/dpmaster/src/system.c
===================================================================
--- trunk/dpmaster/src/system.c	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/system.c	2011-07-18 21:17:24 UTC (rev 11248)
@@ -3,7 +3,7 @@
 
 	System specific code for dpmaster
 
-	Copyright (C) 2008-2010  Mathieu Olivier
+	Copyright (C) 2008-2011  Mathieu Olivier
 
 	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
@@ -771,22 +771,3 @@
 	}
 #endif
 }
-
-
-/*
-====================
-Sys_IsListeningOn
-
-Are we listening on an address of the given family?
-====================
-*/
-qboolean Sys_IsListeningOn (sa_family_t addr_family)
-{
-	unsigned int sock_ind;
-
-	for (sock_ind = 0; sock_ind < nb_sockets; sock_ind++)
-		if (listen_sockets[sock_ind].local_addr.ss_family == addr_family)
-			return true;
-
-	return false;
-}

Modified: trunk/dpmaster/src/system.h
===================================================================
--- trunk/dpmaster/src/system.h	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/src/system.h	2011-07-18 21:17:24 UTC (rev 11248)
@@ -3,7 +3,7 @@
 
 	System specific code for dpmaster
 
-	Copyright (C) 2008-2009  Mathieu Olivier
+	Copyright (C) 2008-2011  Mathieu Olivier
 
 	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
@@ -156,8 +156,5 @@
 // Get the last network error string
 const char* Sys_GetLastNetErrorString (void);
 
-// Are we listening on an address of the given family?
-qboolean Sys_IsListeningOn (sa_family_t addr_family); 
 
-
 #endif  // #ifndef _SYSTEM_H_

Modified: trunk/dpmaster/testsuite/query_remote_master.pl
===================================================================
--- trunk/dpmaster/testsuite/query_remote_master.pl	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/testsuite/query_remote_master.pl	2011-07-18 21:17:24 UTC (rev 11248)
@@ -92,4 +92,4 @@
 	Client_SetProperty ($clientRef, "useIPv6", 1);
 }
 
-Test_Run ("Querying $masterAddr for $gamename servers (protocol: $protocol)...", 1);
+Test_Run ("Querying $masterAddr for $gamename servers (protocol: $protocol)...", 3, 1);

Added: trunk/dpmaster/testsuite/test-flood_protection.pl
===================================================================
--- trunk/dpmaster/testsuite/test-flood_protection.pl	                        (rev 0)
+++ trunk/dpmaster/testsuite/test-flood_protection.pl	2011-07-18 21:17:24 UTC (rev 11248)
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+use strict;
+use testlib;
+
+
+Master_SetProperty ("floodProtectionThrottle", 4);
+Master_SetProperty ("hashPorts", 0);
+
+my $serverRef = Server_New ();
+
+my $client1Ref = Client_New ();
+my $client2Ref = Client_New ();
+my $client3Ref = Client_New ();
+my $client4Ref = Client_New ();
+
+# The 4th request should be ignored
+Client_SetProperty ($client4Ref, "cannotBeAnswered", 1);
+Test_Run ("Flood protection (no retry)");
+
+# The 4th client should be able to get an answer after a 3 sec delay
+Client_SetProperty ($client4Ref, "cannotBeAnswered", 0);
+Client_SetProperty ($client4Ref, "retryDelay", 3);
+Test_Run ("Flood protection (retry after 3 sec)", 5);


Property changes on: trunk/dpmaster/testsuite/test-flood_protection.pl
___________________________________________________________________
Name: svn:executable
   + *

Modified: trunk/dpmaster/testsuite/testlib.pm
===================================================================
--- trunk/dpmaster/testsuite/testlib.pm	2011-07-16 18:54:18 UTC (rev 11247)
+++ trunk/dpmaster/testsuite/testlib.pm	2011-07-18 21:17:24 UTC (rev 11248)
@@ -47,6 +47,7 @@
 
 	# Command line options
 	allowLoopback => 1,
+	floodProtectionThrottle => undef,
 	gamePolicy => undef,
 	hashPorts => 1,
 	maxNbServers => undef,
@@ -226,19 +227,21 @@
 sub Client_CheckServerList {
 	my $clientRef = shift;
 	
-	if ($clientRef->{serverListCount} > 0) {
-		if ($clientRef->{cannotBeAnswered}) {
-			push @failureDiagnostic, "Client_CheckServerList: client $clientRef->{id} shouldn't have got any response, but it got $clientRef->{serverListCount}";
-			return 0;
-		}
-	}
-	else {
+	# If this client got no answer
+	if ($clientRef->{serverListCount} == 0) {
 		if (not $clientRef->{cannotBeAnswered}) {
 			push @failureDiagnostic, "Client_CheckServerList: client $clientRef->{id} should have received a response, but it did not";
 			return 0;
 		}
+
+		return 1;
 	}
 
+	if ($clientRef->{cannotBeAnswered}) {
+		push @failureDiagnostic, "Client_CheckServerList: client $clientRef->{id} shouldn't have got any response, but it got $clientRef->{serverListCount}";
+		return 0;
+	}
+
 	my $clUseIPv6 = $clientRef->{useIPv6};
 	my $clPropertiesRef = $clientRef->{gameProperties};
 	my $clGamename = $clPropertiesRef->{gamename};
@@ -397,15 +400,17 @@
 		family => $gameFamily,
 		id => $id,
 		state => undef,  # undef -> Init -> WaitingServerList -> Done
+		lastRequestTime => 0,
 		port => $port,
 		socket => undef,
 		serverList => {},
 		serverListCount => 0,  # Nb of server lists received
 		alwaysUseExtendedQuery => 0,
-		cannotBeAnswered => 0,
+		cannotBeAnswered => undef,
 		useIPv6 => 0,
 		queryFilters => $queryFilters,
 		ignoreEOTMarks => 0,
+		retryDelay => undef,
 
 		gameProperties => {
 			gamename => $gamename,
@@ -462,6 +467,15 @@
 				die "Invalid message received while waiting for the server list";
 			}
 		}
+		
+		if ($clientRef->{serverListCount} == 0) {
+			if (defined ($clientRef->{retryDelay})) {
+				# If enough time has passed since our last request, try one more time to get an answer 
+				if ($clientRef->{lastRequestTime} + $clientRef->{retryDelay} <= $currentTime) {
+					Client_SendGetServers ($clientRef);
+				}
+			}
+		}
 	}
 
 	# "Done" state
@@ -536,8 +550,11 @@
 	}
 
 	send ($clientRef->{socket}, $getservers, 0) or die "Can't send packet: $!";
+	$clientRef->{lastRequestTime} = $currentTime;
 
-	$clientRef->{cannotBeAnswered} = not (Client_ValidateGetServers ($getservers) and Master_IsGameAccepted ($gameProp->{gamename}));
+	if (not defined $clientRef->{cannotBeAnswered}) {
+		$clientRef->{cannotBeAnswered} = not (Client_ValidateGetServers ($getservers) and Master_IsGameAccepted ($gameProp->{gamename}));
+	}
 }
 
 
@@ -576,6 +593,7 @@
 
 	$clientRef->{socket} = Common_CreateSocket ($clientRef->{port}, $clientRef->{useIPv6});
 	$clientRef->{state} = "Init";
+	$clientRef->{lastRequestTime} = 0;
 }
 
 	
@@ -594,6 +612,8 @@
 	# Clean the server list
 	$clientRef->{serverList} = {};
 	$clientRef->{serverListCount} = 0;
+	
+	$clientRef->{cannotBeAnswered} = undef;
 }
 
 	
@@ -734,6 +754,10 @@
 		$dpmasterCmdLine .= " -n $dpmasterProperties{maxNbServers}";
 	}
 	
+	if (defined $dpmasterProperties{floodProtectionThrottle}) {
+		$dpmasterCmdLine .= " -f --fp-throttle $dpmasterProperties{floodProtectionThrottle}";
+	}
+	
 	# "--hash-ports" and "-N" are mutually incompatible options
 	if (defined $dpmasterProperties{maxNbServersPerAddr}) {
 		$dpmasterCmdLine .= " -N $dpmasterProperties{maxNbServersPerAddr}";
@@ -1150,6 +1174,7 @@
 #***************************************************************************
 sub Test_Run {
 	my $testTitle = shift;
+	my $testDuration = shift;
 	my $skipServerListCheck = shift;
 	
 	$testNumber++;
@@ -1163,7 +1188,10 @@
 
 	Test_StartAll ();
 
-	my $testTime = $currentTime + 3;  # 3 sec of test
+	if (not defined ($testDuration)) {
+		$testDuration = 3;  # 3 sec of test, by default
+	}
+	my $testTime = $currentTime + $testDuration;
 	my $exitValue = undef;
 
 	for (;;) {



More information about the twilight-commits mailing list