diff options
| -rw-r--r-- | CHANGELOG | 7 | ||||
| -rwxr-xr-x | README | 61 | ||||
| -rwxr-xr-x | data/masterserver-config.pl | 196 | ||||
| -rwxr-xr-x | data/sql/tables-Pg.sql | 1 | ||||
| -rwxr-xr-x | data/sql/tables-SQLite.sql | 8 | ||||
| -rwxr-xr-x | data/supportedgames.pl | 16 | ||||
| -rwxr-xr-x | lib/MasterServer/Core/Logging.pm | 10 | ||||
| -rwxr-xr-x | lib/MasterServer/Core/Schedulers.pm | 7 | ||||
| -rwxr-xr-x | lib/MasterServer/Core/Util.pm | 4 | ||||
| -rwxr-xr-x | lib/MasterServer/Core/Version.pm | 4 | ||||
| -rwxr-xr-x | lib/MasterServer/Database/SQLite/dbAddServers.pm | 2 | ||||
| -rwxr-xr-x | lib/MasterServer/Database/SQLite/dbExtendedInfo.pm | 88 | ||||
| -rwxr-xr-x | lib/MasterServer/Database/SQLite/dbGetServers.pm | 2 | ||||
| -rwxr-xr-x | lib/MasterServer/Database/SQLite/dbMaintenance.pm | 2 | ||||
| -rwxr-xr-x | lib/MasterServer/Database/SQLite/dbStats.pm | 2 | ||||
| -rwxr-xr-x | lib/MasterServer/Database/SQLite/dbUTServerInfo.pm | 122 | ||||
| -rwxr-xr-x | lib/MasterServer/UDP/BeaconCatcher.pm | 3 | ||||
| -rwxr-xr-x | lib/MasterServer/UDP/DatagramProcessor.pm | 16 | ||||
| -rwxr-xr-x | lib/MasterServer/UDP/UDPTicker.pm | 5 | ||||
| -rwxr-xr-x | lib/MasterServer/UDP/UpLink.pm | 24 | ||||
| -rwxr-xr-x | util/masterserver.pl | 2 |
21 files changed, 242 insertions, 340 deletions
@@ -4,6 +4,13 @@ AUTHOR darkelarious@333networks.com CHANGELOG +2.4.1 - 25 Sep 2017 + * player uplink query removed, generates too much unnecessary traffic + * reject local IPs like 192.168.*.*, 10.0.*.* and 127.0.*.* + * detailed and comprehensible information for every game server, not just UT + * new masterservers automatically synchronize with each other, two-way + * numerous bug fixes including SQLite 'boolean' behavior + 2.4.0 - 22 Aug 2017 * fundamental changes in behaviour * no longer authenticate on the uplink port, but query port @@ -24,13 +24,13 @@ AUTHOR REQUIREMENTS - - Postgresql, MySQL or SQLite3 + - Postgresql, SQLite3 - Perl 5.10 or above - The following CPAN modules: AnyEvent AnyEvent::Handle::UDP DBI - DBD::Pg / DBD::SQLite / DBD::mysql + DBD::Pg / DBD::SQLite Encode Exporter IP::Country::Fast @@ -44,7 +44,7 @@ INSTALL THE MASTER SERVER IS WRITTEN ON LINUX. IF YOU WANT TO RUN THE SOFTWARE IN MICROSOFT WINDOWS OR APPLE OSX, IT WILL NOT WORK WITHOUT MODIFICATIONS. - Download the masterserver files from our GIT repository (or zip) and extract + Download the masterserver files from our git repository (or zip) and extract them to your favorite server directory. The masterserver stores server addresses in the database. This database must @@ -52,7 +52,8 @@ INSTALL file with read/write access. The tables to be created can be found in the "data/sql" folder in the tables-Pg/SQLite/mysql.sql file. Choose your preferred database driver and create the tables by importing the SQL file or - by manually creating the tables with your SQL shell. + by manually creating the tables with your SQL shell. SQLite users can use the + included util/create-sqlite-database.sh to create their database. This repository consists of Perl modules and is run in terminal. The software utilizes UDP and TCP connections to receive and send information about game @@ -207,7 +208,7 @@ CONFIGURATION do not want other people querying your masterserver, then why are you running a masterserver in the first place? - We do not want authorized people mass-spamming our (or other's) masterservers + We do not want authorized people spamming our (or other's) masterservers with sync request to determine whether the server is online (yes, this actually happens -- use the \status\ query for that!) or to keep the list unnecessary updated. Sync requests should not be executed more than 1-2 times @@ -219,12 +220,12 @@ RUNNING After all CPAN modules have been installed and all options have been reviewed in the configuration file, the masterserver can be started with the following - command from within the root directory of this folder: + command from within the util directory of this folder: - screen -dmS "masterserver" ./util/masterserver.pl + screen -dmS "masterserver" ./masterserver.pl - You can also choose to run the masterserver with ./util/masterserver without - the use of a terminal multiplexer, for example for debugging purposes or a + You can also choose to run the masterserver with ./masterserver without the + use of a terminal multiplexer, for example for debugging purposes or a dry-run to test if your settings are properly configured. The masterserver works great in combination with one of the MasterServer @@ -249,12 +250,21 @@ TOOLS included in the repository. Poor documentation is included in the scripts and in the required files themselves. Do not forget to change database settings per tool. Expert knowledge required! + These tools will move to a new repository on our git soon. KNOWN ISSUES There are a few known issues that will be resolved in future versions. The following issues are listed and do not need to be reported. + This README file is unnecessary long. Over the time we have added a lot of + functions and therefore a lot of documentation. This README file becomes + bloated with things everybody already knows or does not intend to use. There + is an initiative to write the masterserver documentation in a single document + that is more focused on comprehensively outlining the fundamentals of the + masterserver, its functions and how to use it. For now, we are stuck with this + in-depth, redundant and waaay too long README file. + MySQL has not been tested with this masterserver version. When any database other than Postgresql or SQLite3 is selected, the masterserver may crash. Support for MySQL will follow at some point, hopefully late 2017. @@ -275,34 +285,9 @@ KNOWN ISSUES for 333networks and affiliated servers do not suffer from this problem. No servers found after syncing with 333networks or others: the syncing - protocol also requires authentication. We do not want people mass-spamming - our (or other's) masterservers with unnecessarily fast sync request. If you - want to sync with us, please email us on info@333networks.com + protocol also requires authentication. We do not want people spamming our + (or other's) masterservers with unnecessarily fast sync request. If you want + to sync with us, please email us on info@333networks.com COPYING - - Copyright (c) 2005-2017 Darkelarious & 333networks.com - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - All Unreal Tournament related materials are based on Epic Games' Unreal - Tournament. UNREAL (c)1999 Epic Megagames, Inc. All Rights Reserved. - Distributed by GT Interactive Software, Inc. under license. UNREAL and the - UNREAL logo are registered trademarks of Epic Megagames, Inc. + See file COPYING diff --git a/data/masterserver-config.pl b/data/masterserver-config.pl index 19d166b..51306a6 100755 --- a/data/masterserver-config.pl +++ b/data/masterserver-config.pl @@ -1,41 +1,45 @@ package MasterServer; - -# -# Last update: 22 Aug 2017 -# - our (%S, $ROOT); -our %S = ( - # preserve root path - root => $ROOT, - ################################################################################ -# Masterserver HOST information # +# Masterserver configuration # +# # +# Review the following settings and edit the values to fit your situation. # # # -# Please fill in your contact details here, for two-way synchronization and # -# for your users to be able to contact you. # +# Please fill in your contact details correctly, as this is shown publicly and # +# on other masterservers. See README for more details. # # # # Values may not contain backslashes and quotes: no \ or \\, nor ' and ", # # unless you know exactly what you're doing! # # # +# Supported Games. # +# The masterserver requires ciphers and gamenames configured in the database # +# to function. # +require "$ROOT/data/supportedgames.pl"; # +# Note that adding a game does not necessarily mean that suddenly the protocol # +# will be supported. The above file only provides the necessary parameters. # +# # +# Last configuration update: 25 Sep 2017 # +# # ################################################################################ - # our public display name (shows in "online masterservers" on 333networks.com) - masterserver_hostname => "master.333networks.com (333networks MasterServer Template)", +our %S = ( + %S, root => $ROOT, + +# Masterserver HOST information +# Please fill in your contact details correctly, as this is shown publicly +# and on other masterservers. + + # masterserver address (optional: nickname or clan) + masterserver_hostname => "master.example.com (My MasterServer Name)", - # contact details (shows in TCP requests directly from master to master) + # contact details masterserver_name => 'Your Name Here', masterserver_contact => 'info@example.com', - masterserver_address => 'master.example.com', -################################################################################ -# Database Login Configuration # -# # -# Login credentials for the database that was created manually before. # -# Yes, that means that you need to create the database and tables on your own. # -# Use only one option: Postgresql, SQLite, MySQL (not tested with MySQL) # -# # -################################################################################ + +# Database Login Configuration +# Login credentials for the database that was created manually before. +# Supported types: Postgresql, SQLite # Postgresql dblogin => ['dbi:Pg:dbname=masterserver', 'user', 'password'], @@ -43,23 +47,17 @@ our %S = ( # SQLite #dblogin => ["dbi:SQLite:dbname=$ROOT/data/masterserver.db",'',''], - # MySQL - #dblogin => ["dbi:mysql:database=masterserver;host=localhost;port=3306",'user','password'], - - # backup database dump + # Backup interval # new backup for every period of time? options: daily, weekly, monthly, yearly, none dump_db => "daily", - -################################################################################ -# Logging configuration # -# # -# All messages are printed to the log (and screen) by default. The following # -# settings determine the file location and which messages are suppressed. # -# # -################################################################################ - # log file location (folder name!) - log_dir => "$ROOT/log/", + +# Logging +# All messages are printed to the log (and screen) by default. The following +# settings determine the file location and which messages are suppressed. + + # log file location (folder name) + log_dir => "$ROOT/log/", # new log for every period of time? options: daily, weekly, monthly, yearly, none log_rotate => "weekly", @@ -68,12 +66,10 @@ our %S = ( printlog => 1, # which messages do you NOT want to see in the logs (and screen)? + # show all entries #suppress => "none", - # show only important events - suppress => "debug beacon uplink secure tcp add update delete", - # keywords that can be suppressed (from high to low severity): # fatal fail error stop # refused nodevice timeout @@ -84,33 +80,28 @@ our %S = ( # stat kfnew # info debug -################################################################################ -# Network settings # -# # -# Beacon UDP port (beacons) and Browser TCP port (serverlist) # -# # -################################################################################ - - # port settings - listen_port => 28900, # default 28900 - beacon_port => 27900, # default 27900 - - # Timeout time for connections. Some clients are on slow connections - # or are queued for a relatively long time. Recommended: 5s - timeout_time => 10, + # show only important events + suppress => "debug beacon uplink secure tcp add update delete", + + +# Network settings +# Port settings and timeouts -################################################################################ -# Secure/Validate configuration # -# # -# Which servers have to validate? Which games may be ignored? # -# # -################################################################################ + # TCP/client port, default 28900 + listen_port => 28900, + + # UDP/uplink port, default 27900 + beacon_port => 27900, - # disable checks, all games pass as validated (0=validate only, 1=don't check) - debug_validate => 0, + # Timeout time for connections. Recommended: 5 (seconds) + timeout_time => 5, + - # accept only servers that pass the secure/validate challenge, takes longer - # but prevents malicious servers from sending fake query data +# Secure/Validate configuration +# Which servers have to authenticate? + + # accept only servers that can authenticate. takes longer before adding to the + # database, but prevents malicious servers from sending fake query data require_secure_beacons => 1, # ignore keys from games that use multiple keys or do not support keys at all @@ -119,35 +110,17 @@ our %S = ( # some games do not even support the "secure" and "validate" values. Bypass. secure_unsupported => "tribesv", - -################################################################################ -# Enable settings # -# # -# 0 = disabled # -# # -################################################################################ - # Query UCC-based applets - master_applet_enabled => 1, + +# Synchronization settings +# Send beacons to the following selected masterservers. This joins us in the +# 333networks network and makes two-way synchronization possible for all games +# or only selected games. Requires at least one entry to a live masterserver. # Synchronization with other 333networks-based masterservers sync_enabled => 1, - # Beacon Checker - # getting server status info from \all\ servers. executed every 15 minutes to - # keep information up to date. - # disabling breaks support for certain games [like tribesv]. - beacon_checker_enabled => 1, - -################################################################################ -# Synchronization settings # -# # -# Send beacons to the following selected masterservers. This joins us in the # -# 333networks network and makes two-way synchronization possible for all games # -# or only selected games. Requires at least one entry to a live masterserver. # -################################################################################ - - # default masterservers to uplink to + # default masterservers to uplink to and synchronize with sync_masters => [ { address => "master.333networks.com", port => 28900, beacon => 27900 }, { address => "master.noccer.de", port => 28900, beacon => 27900 }, @@ -161,28 +134,26 @@ our %S = ( # other example: [1 + gamenames] = selected games only #sync_games => [1, "ut unreal deusex"], - -################################################################################ -# Query UCC Applets # -# # -# Request the masterlist for single games from the remote UCC applet or # -# equivalent. # -# # -# Arguments: domain/ip, tcp port, array of gamenames # -################################################################################ + + # getting server status info from all servers. executed every 15 minutes to + # keep information up to date. disabling breaks support for certain games + # like tribesv. + beacon_checker_enabled => 1, + +# Query UCC-based Applets +# Request the masterlist for single games from the remote UCC applet -- one way + master_applet_enabled => 1, + + # default applets to query master_applet => [ {address => "utmaster.epicgames.com", port => 28900, games => [qw|ut unreal|]}, {address => "master.hypercoop.tk", port => 28900, games => [qw|unreal|]}, - {address => "sof1master.megalag.org", port => 28900, games => [qw|sofretail|]}, - {address => "master.deusexnetwork.com", port => 28900, games => [qw|deusex|]}, ], -################################################################################ -# Killing Floor Statistics # -# # -# Read player statistics from the KFstats file in the UT2004 configuration. # -# Applies to 333networks Killing Floor Server only! # -################################################################################ +# Killing Floor Statistics +# 333networks has a UT2004+KillingFloor server for which we maintain statistics. +# not related to the masterserver, but we felt no need to remove it. Set to 0 if +# you do not use it. # Collect kfstats info kfstats_enabled => 0, @@ -190,17 +161,6 @@ our %S = ( # kfstats.ini file location kfstats_file => "/UT2004/System/KFStats.ini", -); #end configuration %S - -################################################################################ -# # -# Supported Games. # -# # -# List of games that are supported by the 333networks masterserver. Note that # -# adding a game does not necessarily mean that suddenly the protocol will # -# be supported. It only needs the provided ciphers. # -# # -################################################################################ -require "$ROOT/data/supportedgames.pl"; +); 1; diff --git a/data/sql/tables-Pg.sql b/data/sql/tables-Pg.sql index ab68d61..96f8f91 100755 --- a/data/sql/tables-Pg.sql +++ b/data/sql/tables-Pg.sql @@ -101,4 +101,3 @@ CREATE TABLE kfstats( GamesWon INTEGER NOT NULL DEFAULT 0, GamesLost INTEGER NOT NULL DEFAULT 0 ); - diff --git a/data/sql/tables-SQLite.sql b/data/sql/tables-SQLite.sql index 80df6b4..5608a66 100755 --- a/data/sql/tables-SQLite.sql +++ b/data/sql/tables-SQLite.sql @@ -16,8 +16,8 @@ CREATE TABLE serverlist( hostname TEXT, hostport INTEGER DEFAULT 0, country TEXT, - b333ms BOOLEAN DEFAULT FALSE, - blacklisted BOOLEAN DEFAULT FALSE, + b333ms INTEGER DEFAULT 0, + blacklisted INTEGER DEFAULT 0, added timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, beacon timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, updated timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -43,7 +43,7 @@ CREATE TABLE pending( added timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE TABLE utserver_info( +CREATE TABLE extended_info( server_id INTEGER PRIMARY KEY AUTOINCREMENT, minnetver TEXT, location TEXT, @@ -72,7 +72,7 @@ CREATE TABLE utserver_info( FOREIGN KEY(server_id) REFERENCES serverlist(id) ); -CREATE TABLE utplayer_info( +CREATE TABLE player_info( server_id INTEGER NOT NULL, player TEXT DEFAULT 'Player', team TEXT, diff --git a/data/supportedgames.pl b/data/supportedgames.pl index 18fe83f..3df5234 100755 --- a/data/supportedgames.pl +++ b/data/supportedgames.pl @@ -1,16 +1,16 @@ -our %S = ( -%S, # do not overwrite other parts of the %S config hash - +our %S = (%S, # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# last change 24 Oktober 2016 +# last change 25 September 2017 +# Changelog 25 Sep 2017: Minor edit in comments. Supportedgames.pl will be completely +# revised/reduced to only provide support for actually functional +# games/protocols. # # Changelog 24 Okt 2016: Added/updated description for the 333networks synchronization # protocol and uplink setup. Works with MS-Perl 2.1.8 and above. -# # -# Changelog 8 Nov 2015: migrated supportedgames.pl to database; after these are games +# Changelog 8 Nov 2015: migrated supportedgames.pl to database; after these games # are loaded, the variables are cleared # # ChangeLog 5 Oct 2015: moved "enc_chars" to Core::Secure.pm, in preparation to @@ -28,7 +28,7 @@ our %S = ( # opportunists to provide fake data or request the data without authorization. # See option "require_secure_beacons" in the configuration file. # -# For questions contact darkelarious@333networks.com or visit at irc. +# For questions contact info@333networks.com or visit at irc. # irc.synirc.net #333networks # # NOTE: DUPLICATES MAY NOT EXIST. IN CASE OF DUPLICATES, ONE OF THE VALUES @@ -39,7 +39,7 @@ our %S = ( # Usage: # game code => {key => "game key", label => "game name label", port => "default port number"} game => { - "333networks" => {key => "", label => "333networks MasterServer (Synchronization Protocol)"}, + "333networks" => {key => "", label => "333networks Masterserver Synchronization"}, "12ironds" => {key => "", label => "12Iron (DS)"}, "12irondsam" => {key => "", label => "12Iron Automatch (DS)"}, "2kboxingds" => {key => "", label => "2K Boxing (DS)"}, diff --git a/lib/MasterServer/Core/Logging.pm b/lib/MasterServer/Core/Logging.pm index d2094ed..260b379 100755 --- a/lib/MasterServer/Core/Logging.pm +++ b/lib/MasterServer/Core/Logging.pm @@ -18,15 +18,15 @@ sub error { # which one? switch ($error) { # connection timed out - case m/Connection timed out/i {$self->log("timeout", "on $instigator.");} + case m/Connection timed out/i {$self->log("timeout", "on $instigator");} # connection reset by peer - case m/Connection reset by peer/i {$self->log("reset", "on $instigator.");} + case m/Connection reset by peer/i {$self->log("reset", "on $instigator");} # connection refused - case m/Connection refused/i {$self->log("refused", "on $instigator.");} + case m/Connection refused/i {$self->log("refused", "on $instigator");} # no such device or address - case m/No such device or address/i {$self->log("nodevice", "on $instigator.");} + case m/No such device or address/i {$self->log("nodevice", "on $instigator");} # if all else fails - else {$self->log("error", "$error on $instigator.");} + else {$self->log("error", "$error on $instigator");} } } diff --git a/lib/MasterServer/Core/Schedulers.pm b/lib/MasterServer/Core/Schedulers.pm index 230a423..fa47d11 100755 --- a/lib/MasterServer/Core/Schedulers.pm +++ b/lib/MasterServer/Core/Schedulers.pm @@ -18,7 +18,7 @@ sub long_periodic_tasks { return AnyEvent->timer ( after => 90, # grace time receiving beacons - interval => 3600, + interval => 1800, cb => sub { # update Killing Floor stats @@ -37,8 +37,9 @@ sub long_periodic_tasks { # get serverlist my $masterserverlist = $self->get_server( - updated => 7200, gamename => "333networks", + $self->{firstrun} ? ( + updated => 7200 ) : (), ); foreach my $ms (@{$masterserverlist}) { @@ -53,7 +54,7 @@ sub long_periodic_tasks { # do NOT reset $t, keep padding time -- you should not have more than 300 # entries in applets/syncer in total anyway. - # Query Epic Games-based UCC applets periodically to get an additional + # Query Epic Games-alike applets periodically to get an additional # list of online UT, Unreal and other game servers. if ($self->{master_applet_enabled}) { diff --git a/lib/MasterServer/Core/Util.pm b/lib/MasterServer/Core/Util.pm index 5af8264..3ca009d 100755 --- a/lib/MasterServer/Core/Util.pm +++ b/lib/MasterServer/Core/Util.pm @@ -54,8 +54,8 @@ sub valid_address { my $val_addr = ($a =~ '^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$') if $a; my $val_port = ($p =~ m/^\d+$/ && 0 < $p && $p <= 65535) if $p; - # exclude addresses where we don't want people sniffing - for (qw|192.168.(.\d*).(.\d*) 127.0.(.\d*).(.\d*) 10.0.(.\d*).(.\d*)|){$val_addr = 0 if ($a =~ m/$_/)} + # exclude local addresses + if ($a =~ m/192.168.(\d).(\d)/ || $a =~ m/127.0.(\d).(\d)/ || $a =~ m/10.0.(\d).(\d)/) { $val_addr = 0; } # only return true if both are valid return ($val_addr && $val_port); diff --git a/lib/MasterServer/Core/Version.pm b/lib/MasterServer/Core/Version.pm index 0b4d058..277cd04 100755 --- a/lib/MasterServer/Core/Version.pm +++ b/lib/MasterServer/Core/Version.pm @@ -27,13 +27,13 @@ sub version { $self->{build_type} = "333networks Masterserver-Perl Multidb"; # version - $self->{build_version} = "2.4.0"; + $self->{build_version} = "2.4.1"; # short version for uplinks $self->{short_version} = "MS-perl $self->{build_version}"; # date yyyy-mm-dd - $self->{build_date} = "2017-08-22"; + $self->{build_date} = "2017-09-25"; #author, email $self->{build_author} = "Darkelarious, darkelarious\@333networks.com"; diff --git a/lib/MasterServer/Database/SQLite/dbAddServers.pm b/lib/MasterServer/Database/SQLite/dbAddServers.pm index 88b1bc8..084e0b4 100755 --- a/lib/MasterServer/Database/SQLite/dbAddServers.pm +++ b/lib/MasterServer/Database/SQLite/dbAddServers.pm @@ -44,7 +44,7 @@ sub update_server { $o{gamever} ? ( 'gamever = ?' => $o{gamever}) : (), $o{hostname} ? ('hostname = ?' => $o{hostname}) : (), $o{hostport} ? ('hostport = ?' => $o{hostport}) : (), - $o{direct} ? ( 'b333ms = CAST(? AS BOOLEAN)' => $o{direct}) : (), + $o{direct} ? ( 'b333ms = ?' => $o{direct}) : (), $o{direct} ? ( 'beacon = datetime(?, \'unixepoch\')' => $o{updated}) : (), $o{updated} ? ( 'updated = datetime(?, \'unixepoch\')' => $o{updated}) : (), ); diff --git a/lib/MasterServer/Database/SQLite/dbExtendedInfo.pm b/lib/MasterServer/Database/SQLite/dbExtendedInfo.pm new file mode 100755 index 0000000..e2eb1bc --- /dev/null +++ b/lib/MasterServer/Database/SQLite/dbExtendedInfo.pm @@ -0,0 +1,88 @@ +package MasterServer::Database::SQLite::dbExtendedInfo; + +use strict; +use warnings; +use MasterServer::Core::Util 'sqlprint'; +use Exporter 'import'; +our @EXPORT = qw| insert_extended + update_extended + delete_players + insert_players |; + +################################################################################ +## Add extended server information for a new server. +## opts: ipm hostport +################################################################################ +sub insert_extended { + my $self = shift; + my %o = ( @_); + return $self->{dbh}->do( + "INSERT INTO extended_info (server_id) + SELECT (SELECT id FROM serverlist WHERE ip = ? AND hostport = ?)", + undef, $o{ip}, $o{hostport}); +} + +################################################################################ +## Update serverinfo for an existing address to the utserver list. +## opts: all server info data fields. +################################################################################ +sub update_extended { + my $self = shift; + my %o = (updated => time, @_); + + # try updating it in serverlist + my %H = ( + $o{minnetver} ? ( 'minnetver = ?' => $o{minnetver} ) : (), + $o{location} ? ( 'location = ?' => $o{location} ) : (), + $o{listenserver} ? ( 'listenserver = ?' => $o{listenserver}) : (), + $o{AdminName} ? ( 'adminname = ?' => $o{AdminName}) : (), + $o{AdminEMail} ? ( 'adminemail = ?' => $o{AdminEMail}) : (), + $o{password} ? ( 'password = ?' => $o{password}) : (), + $o{gametype} ? ( 'gametype = ?' => $o{gametype}) : (), + $o{gamestyle} ? ( 'gamestyle = ?' => $o{gamestyle}) : (), + $o{changelevels} ? ( 'changelevels = ?' => $o{changelevels}) : (), + $o{maptitle} ? ( 'maptitle = ?' => $o{maptitle}) : (), + $o{mapname} ? ( 'mapname = ?' => $o{mapname}) : (), + $o{numplayers} ? ( 'numplayers = ?' => $o{numplayers}) : ('numplayers = ?' => 0), + $o{maxplayers} ? ( 'maxplayers = ?' => $o{maxplayers}) : ('maxplayers = ?' => 0), + $o{minplayers} ? ( 'minplayers = ?' => $o{minplayers}) : ('minplayers = ?' => 0), + $o{botskill} ? ( 'botskill = ?' => $o{botskill}) : (), + $o{balanceteams} ? ( 'balanceteams = ?' => $o{balanceteams} ) : (), + $o{playersbalanceteams} ? ( 'playersbalanceteams = ?' => $o{playersbalanceteams}) : (), + $o{friendlyfire} ? ( 'friendlyfire = ?' => $o{friendlyfire}) : (), + $o{maxteams} ? ( 'maxteams = ?' => $o{maxteams}) : (), + $o{timelimit} ? ( 'timelimit = ?' => $o{timelimit}) : (), + $o{goalteamscore} ? ( 'goalteamscore = ?' => $o{goalteamscore}) : (), + $o{fraglimit} ? ( 'fraglimit = ?' => $o{fraglimit}) : (), + $o{mutators} ? ( 'mutators = ?' => $o{mutators}) : ('mutators = ?' => "None"), + $o{updated} ? ( 'updated = datetime(?, \'unixepoch\')' => $o{updated}) : (), + ); + + my($q, @p) = sqlprint("UPDATE extended_info !H WHERE server_id = ?", \%H, $o{sid}); + return $self->{dbh}->do($q, undef, @p); +} + +################################################################################ +## Delete all players from a certain server ID +## opts: server id +################################################################################ +sub delete_players { + my ($self, $sid) = @_; + + # delete players with server_id + return $self->{dbh}->do( + "DELETE FROM player_info WHERE server_id = ?", + undef, $sid); +} + +################################################################################ +## Insert player info for a single player in server sid +## opts: server id, player info +################################################################################ +sub insert_players { + my ($self, @pl) = @_; + my($q, @p) = sqlprint("INSERT INTO player_info (server_id, player, team, frags, mesh, skin, face, ping, ngsecret) VALUES (!l)", \@pl); + return $self->{dbh}->do($q, undef, @p); +} + +1; diff --git a/lib/MasterServer/Database/SQLite/dbGetServers.pm b/lib/MasterServer/Database/SQLite/dbGetServers.pm index 7ddce2b..e899485 100755 --- a/lib/MasterServer/Database/SQLite/dbGetServers.pm +++ b/lib/MasterServer/Database/SQLite/dbGetServers.pm @@ -31,7 +31,7 @@ sub get_server { $o{before} ? ('updated < datetime(?, \'unixepoch\')' => (time-$o{before})) : (), # never process blacklisted servers, unless explicitly specified - ('blacklisted = CAST(? AS BOOLEAN)' => $o{blacklisted}), + ('blacklisted = ?' => $o{blacklisted}), ); my @select = ( qw| diff --git a/lib/MasterServer/Database/SQLite/dbMaintenance.pm b/lib/MasterServer/Database/SQLite/dbMaintenance.pm index ec9b5cc..a729b2f 100755 --- a/lib/MasterServer/Database/SQLite/dbMaintenance.pm +++ b/lib/MasterServer/Database/SQLite/dbMaintenance.pm @@ -1,4 +1,4 @@ -package MasterServer::Database::Pg::dbMaintenance; +package MasterServer::Database::SQLite::dbMaintenance; use strict; use warnings; diff --git a/lib/MasterServer/Database/SQLite/dbStats.pm b/lib/MasterServer/Database/SQLite/dbStats.pm index 57d3100..0d0b8eb 100755 --- a/lib/MasterServer/Database/SQLite/dbStats.pm +++ b/lib/MasterServer/Database/SQLite/dbStats.pm @@ -69,7 +69,7 @@ sub write_direct_beacons { my $self = shift; my $u = $self->{dbh}->do( "UPDATE serverlist - SET b333ms = CAST(0 AS BOOLEAN) + SET b333ms = 0 WHERE beacon < datetime(?, \'unixepoch\') AND b333ms", undef, time-3600); $self->log("unset", "Lost $u direct beacons.") if ($u > 0); diff --git a/lib/MasterServer/Database/SQLite/dbUTServerInfo.pm b/lib/MasterServer/Database/SQLite/dbUTServerInfo.pm deleted file mode 100755 index 5a579ac..0000000 --- a/lib/MasterServer/Database/SQLite/dbUTServerInfo.pm +++ /dev/null @@ -1,122 +0,0 @@ -package MasterServer::Database::SQLite::dbUTServerInfo; - -use strict; -use warnings; -use MasterServer::Core::Util 'sqlprint'; -use Exporter 'import'; - -our @EXPORT = qw| add_utserver - update_utserver - delete_utplayers - insert_utplayer |; - -################################################################################ -## Update serverinfo for an existing address to the utserver list. -## opts: all server info data fields. -################################################################################ -sub update_utserver { - my $self = shift; - my $id = shift; - my %s = ( - # defaults - updated => time, - @_); - - # try updating it in serverlist - my %H = ( - $s{minnetver} ? ( 'minnetver = ?' => $s{minnetver} ) : (), - $s{gamever} ? ( 'gamever = ?' => int( $s{gamever}) ) : (), - $s{location} ? ( 'location = ?' => $s{location} ) : (), - $s{listenserver} ? ( 'listenserver = ?' => ( $s{listenserver} ? 1 : 0) ) : (), - $s{hostport} ? ( 'hostport = ?' => $s{hostport}) : (), - $s{hostname} ? ( 'hostname = ?' => $s{hostname}) : (), - $s{AdminName} ? ( 'adminname = ?' => $s{AdminName}) : (), - $s{AdminEMail} ? ( 'adminemail = ?' => $s{AdminEMail}) : (), - $s{password} ? ( 'password = ?' => ( $s{password} ? 1 : 0) ) : (), - $s{gametype} ? ( 'gametype = ?' => $s{gametype}) : (), - $s{gamestyle} ? ( 'gamestyle = ?' => $s{gamestyle}) : (), - $s{changelevels} ? ( 'changelevels = ?' => ( $s{changelevels} ? 1 : 0) ) : (), - $s{maptitle} ? ( 'maptitle = ?' => $s{maptitle}) : (), - $s{mapname} ? ( 'mapname = ?' => $s{mapname}) : (), - $s{numplayers} ? ( 'numplayers = ?' => $s{numplayers}) : ('numplayers = ?' => 0), - $s{maxplayers} ? ( 'maxplayers = ?' => $s{maxplayers}) : ('maxplayers = ?' => 0), - $s{minplayers} ? ( 'minplayers = ?' => $s{minplayers}) : ('minplayers = ?' => 0), - $s{botskill} ? ( 'botskill = ?' => $s{botskill}) : (), - $s{balanceteams} ? ( 'balanceteams = ?' => ( $s{balanceteams} ? 1 : 0) ) : (), - $s{playersbalanceteams} ? ( 'playersbalanceteams = ?' => ( $s{playersbalanceteams} ? 1 : 0) ) : (), - $s{friendlyfire} ? ( 'friendlyfire = ?' => $s{friendlyfire}) : (), - $s{maxteams} ? ( 'maxteams = ?' => $s{maxteams}) : (), - $s{timelimit} ? ( 'timelimit = ?' => $s{timelimit}) : (), - $s{goalteamscore} ? ( 'goalteamscore = ?' => int( $s{goalteamscore}) ) : (), - $s{fraglimit} ? ( 'fraglimit = ?' => int( $s{fraglimit}) ) : (), - $s{mutators} ? ( 'mutators = ?' => $s{mutators}) : ('mutators = ?' => "None"), - $s{updated} ? ('updated = datetime(?, \'unixepoch\')' => $s{updated}) : (), - ); - - my($q, @p) = sqlprint("UPDATE utserver_info !H WHERE server_id = ?", \%H, $id); - return $self->{dbh}->do($q, undef, @p); -} - - -################################################################################ -## Add a new utserver and trigger the update routine above. -## opts: id, server info data -################################################################################ -sub add_utserver { - my ($self, $ip, $port) = @_; - - # create new entry - return $self->{dbh}->do( - "INSERT INTO utserver_info (server_id) - SELECT (SELECT id FROM serverlist WHERE ip = ? AND port = ?)", - undef, $ip, $port); -} - - -################################################################################ -## Delete all players from a certain server ID -## opts: server id -################################################################################ -sub delete_utplayers { - my ($self, $sid) = @_; - - # delete players for server_id - return $self->{dbh}->do( - "DELETE FROM utplayer_info WHERE server_id = ?", - undef, $sid); -} - -################################################################################ -## Insert player info for a single player in server sid -## opts: server id, player info -################################################################################ -sub insert_utplayer { - my $self = shift; - my $sid = shift; - my %s = ( - updated => time, - @_); - - # apparently useless chunk of code - # FIXME move to site part - my %H = ( - $s{server_id} ? ( 'server_id = ?' => $s{server_id}) : (), - $s{player} ? ( 'player = ?' => $s{player}) : (), - $s{team} ? ( 'team = ?' => int( $s{team})) : (), - $s{frags} ? ( 'frags = ?' => int( $s{frags})) : (), - $s{mesh} ? ( 'mesh = ?' => $s{mesh}) : (), - $s{skin} ? ( 'skin = ?' => $s{skin}) : (), - $s{face} ? ( 'face = ?' => $s{face}) : (), - $s{ping} ? ( 'ping = ?' => int( $s{ping})) : (), - $s{ngsecret} ? ( 'ngsecret = ?' => $s{ngsecret}) : (), - $s{updated} ? ('updated = datetime(?, \'unixepoch\')' => $s{updated}) : (), - ); - - # insert - return $self->{dbh}->do( - "INSERT INTO utplayer_info (server_id, player, team, frags, mesh, skin, face, ping, ngsecret) - VALUES (?,?,?,?,?,?,?,?,?)", - undef, $sid, $s{player}, $s{team}, $s{frags}, $s{mesh}, $s{skin}, $s{face}, $s{ping}, $s{ngsecret}); -} - -1; diff --git a/lib/MasterServer/UDP/BeaconCatcher.pm b/lib/MasterServer/UDP/BeaconCatcher.pm index 6058bfa..1bfc5b0 100755 --- a/lib/MasterServer/UDP/BeaconCatcher.pm +++ b/lib/MasterServer/UDP/BeaconCatcher.pm @@ -34,6 +34,9 @@ sub recv_beacon { # unpack ip from packed client address my ($port, $iaddr) = sockaddr_in($paddress); my $beacon_address = inet_ntoa($iaddr); + + # ignore localhost and restricted IPs like localhost + return unless $self->valid_address($beacon_address, $port); # determine and process heartbeat if ($buffer =~ m/\\heartbeat\\/) { diff --git a/lib/MasterServer/UDP/DatagramProcessor.pm b/lib/MasterServer/UDP/DatagramProcessor.pm index 5587875..87c23a1 100755 --- a/lib/MasterServer/UDP/DatagramProcessor.pm +++ b/lib/MasterServer/UDP/DatagramProcessor.pm @@ -77,14 +77,12 @@ sub process_datagram { enctype => $rx->{enctype}, validate => $rx->{validate}, ); - $self->log("secure","$o{ip}, $o{port} failed validation for ". - ($rx->{gamename} || "empty_gamename") - ."; sent: '". ($o{secure} || "empty_secure") - ."', expected '". ($val_str || "empty_v_string") - ."', got '". ($rx->{validate} || "empty_r_validate") - ."' with cipher '". ($self->get_game_props(gamename => $rx->{gamename})->[0]->{cipher} || "empty_cipher") - ."'" - ); + $self->log("secure","$o{ip}, $o{port} failed validation for ".($rx->{gamename} || "empty_gamename") ); + $self->log("secure", + "cipher: " .($self->get_game_props(gamename => $rx->{gamename})->[0]->{cipher} || "empty_cipher") . ", " + ."secure: " .($o{secure} || "empty_secure"). ", " + ."expected: " .($val_str || "empty_v_string"). ", " + ."received: " .($rx->{validate} || "empty_r_validate")); # remove addresses anyway to prevent error spamming in log $self->remove_pending(ip => $o{ip}, port => $o{port}); @@ -143,7 +141,7 @@ sub unify_information { my %uei; # unified extended info my @upi; # unified player info - # FIXME unify with player playername name + # FIXME unify with {player playername name, other keys/columns} # first process all available player entries for (my $i = 0; exists $rx->{"player_$i"}; $i++) { diff --git a/lib/MasterServer/UDP/UDPTicker.pm b/lib/MasterServer/UDP/UDPTicker.pm index 0566449..f5673a4 100755 --- a/lib/MasterServer/UDP/UDPTicker.pm +++ b/lib/MasterServer/UDP/UDPTicker.pm @@ -30,8 +30,9 @@ sub udp_ticker { # tick through pending list and server list my $server_info = AnyEvent->timer ( - after => 120, # grace time receiving beacons - interval => 0.2, # ~5 servers/s + after => 120, # grace time receiving beacons -- MUST be the last + # function to start as it controls the first_run parameter + interval => 0.2, # ~5 servers/second cb => sub { # reset counters if minimum time before reset passed + list processed if ($self->{firstrun}) { diff --git a/lib/MasterServer/UDP/UpLink.pm b/lib/MasterServer/UDP/UpLink.pm index d523ad0..16550c3 100755 --- a/lib/MasterServer/UDP/UpLink.pm +++ b/lib/MasterServer/UDP/UpLink.pm @@ -70,8 +70,7 @@ sub do_uplink { } ################################################################################ -## Respond to status-like queries. Supported queries are basic, info, rules, -## players, status. +## Respond to status-like queries. Supported: basic, info, rules, status. ## Note: this replaces the \about\ query in the TCP handler! ################################################################################ sub handle_status_query { @@ -124,31 +123,16 @@ sub handle_status_query { # rules query if (defined $rx->{rules} || defined $rx->{status}) { - $response .= "\\mutators\\333networks synchronization, UCC Master applet synchronization, Display Stats As Players" + $response .= "\\mutators\\333networks synchronization, UCC Master applet synchronization, Server Status Checker" . "\\AdminName\\".($self->{masterserver_name} || "") . "\\AdminEMail\\".($self->{masterserver_contact} || "") . "\\queryid\\$query_id.".$sub_id++; } - - # players query - if (defined $rx->{players} || defined $rx->{status}) { - # list game stats as if they were players. let the client figure out how - # to list this information on their website (hint: that's us) - my $c = 0; - foreach my $p (@{$gameinfo}) { - $response .= "\\player_$c\\".($p->{description} || "") - . "\\team_$c\\" .($p->{gamename} || "") - . "\\skin_$c\\" .($p->{num_total} || 0) . " total" - . "\\mesh_$c\\" .($p->{num_uplink} || 0) . " direct"; - $c++; # start with player_0, increment - } - $response .= "\\queryid\\$query_id.".$sub_id++; - } - + # close query with final tag $response .= "\\final\\"; - # split the response in chunks of 512 bytes and send + # split the response in chunks of 512 characters and send while (length $response > 512) { my $chunk = substr $response, 0, 512, ''; $udp->push_send($chunk, $paddress); diff --git a/util/masterserver.pl b/util/masterserver.pl index d684001..766f59a 100755 --- a/util/masterserver.pl +++ b/util/masterserver.pl @@ -1,7 +1,6 @@ #!/usr/bin/perl package MasterServer; - use strict; use warnings; use Cwd 'abs_path'; @@ -9,7 +8,6 @@ use Cwd 'abs_path'; our $ROOT; BEGIN { ($ROOT = abs_path $0) =~ s{/util/masterserver\.pl$}{}; } use lib $ROOT.'/lib'; - use MasterServer; our %S; |
