aboutsummaryrefslogtreecommitdiff
path: root/lib/MasterServer/Core
diff options
context:
space:
mode:
authorDarkelarious <darkelarious@333networks.com>2017-05-13 14:18:28 +0200
committerDarkelarious <darkelarious@333networks.com>2017-05-13 14:20:49 +0200
commit34a2c7390ea9662d33258d384e72fff1912343ff (patch)
treed96ea33c0107e4906a152aa1de4b5c75b81ba0a8 /lib/MasterServer/Core
parent84af66aba26d2088d5d95c240d176f3edaf17b58 (diff)
downloadMasterServer-Perl-2.3.0.tar.gz
MasterServer-Perl-2.3.0.zip
revised synchronization methods, config settings and bug fixesv2.3.0
Diffstat (limited to 'lib/MasterServer/Core')
-rwxr-xr-xlib/MasterServer/Core/Core.pm32
-rwxr-xr-xlib/MasterServer/Core/LoadConfig.pm150
-rwxr-xr-xlib/MasterServer/Core/Logging.pm30
-rwxr-xr-xlib/MasterServer/Core/Schedulers.pm117
-rwxr-xr-xlib/MasterServer/Core/Secure.pm73
-rwxr-xr-xlib/MasterServer/Core/Stats.pm4
-rwxr-xr-xlib/MasterServer/Core/Util.pm11
-rwxr-xr-xlib/MasterServer/Core/Version.pm7
8 files changed, 290 insertions, 134 deletions
diff --git a/lib/MasterServer/Core/Core.pm b/lib/MasterServer/Core/Core.pm
index be0646b..4d1e47b 100755
--- a/lib/MasterServer/Core/Core.pm
+++ b/lib/MasterServer/Core/Core.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Core;
use strict;
@@ -6,6 +5,7 @@ use warnings;
use AnyEvent;
use Exporter 'import';
use DBI;
+$|++;
our @EXPORT = qw | halt select_database_type main |;
@@ -47,7 +47,7 @@ sub select_database_type {
if ( "Pg SQLite mysql" =~ m/$db_type[1]/i) {
# inform us what DB we try to load
- $self->log("load","Loading $db_type[1] database module.");
+ $self->log("debug","Loading $db_type[1] database module.");
# load dbd and tables/queries for this db type
MasterServer::load_recursive("MasterServer::Database::$db_type[1]");
@@ -74,11 +74,11 @@ sub main {
# condition var prevents or allows the program from ending
$self->{must_halt} = AnyEvent->condvar;
- # force version info
+ # load version info
$self->version();
# print startup
- print "Running...\n";
+ print "Running 333networks Master Server Application...\n";
# keep several objects alive outside their original scope
$self->{scope} = ();
@@ -96,14 +96,24 @@ sub main {
# determine the type of database and load the appropriate module
$self->select_database_type();
+ ###
#
- # Prepare necessary tasks for running the masterserver
+ # execute necessary tasks for running the masterserver
#
+ ###
+
+ # load the list with ciphers from the config file if no ciphers were detected
+ # update manually with util/tools/db_load_ciphers.pl
+ # then unload the game variables from masterserver memory
+ $self->load_ciphers() unless $self->check_cipher_count();
+ $self->{game} = undef;
- # (re)load the list with ciphers from the config file, into the database
- $self->load_ciphers();
+ # (re)load the list with masterservers and master applets from config
+ # does not clear out old entries, but resets "last_updated" to now
+ $self->load_sync_masters();
+ $self->load_applet_masters();
- # set first run flag to avoid ignoring servers after downtime
+ # set first run flag to avoid ignoring/deleting servers after downtime
$self->{firstrun} = undef;
$self->{firstruntime} = time;
@@ -134,10 +144,14 @@ sub main {
# provide server lists to clients with the browser host server
$self->{scope}->{browser_host} = $self->browser_host();
+ ###
+ #
# all modules loaded. Running...
+ #
+ ###
$self->log("info", "All modules loaded. Masterserver is now running.");
- # prevent main program from ending prematurely
+ # prevent main program from ending as long as no fatal errors occur
$self->{must_halt}->recv;
}
diff --git a/lib/MasterServer/Core/LoadConfig.pm b/lib/MasterServer/Core/LoadConfig.pm
new file mode 100755
index 0000000..e209848
--- /dev/null
+++ b/lib/MasterServer/Core/LoadConfig.pm
@@ -0,0 +1,150 @@
+package MasterServer::Core::LoadConfig;
+
+use strict;
+use warnings;
+use AnyEvent;
+use POSIX qw/strftime/;
+use Exporter 'import';
+use DBI;
+
+our @EXPORT = qw | load_applet_masters
+ load_sync_masters
+ add_sync_master |;
+
+################################################################################
+## Load configuration variables to the database, helper functions
+################################################################################
+sub load_applet_masters {
+ my $self = shift;
+
+ # loop through config entries
+ foreach my $master_applet (@{$self->{master_applet}}) {
+ # master_applet contains
+ # address --> domain
+ # port --> tcp port
+ # games --> array of gamenames
+
+ # iterate through all games per entry
+ for my $gamename (@{$master_applet->{games}}) {
+
+ # resolve domain names
+ my $applet_ip = $self->host2ip($master_applet->{address});
+
+ # check if all credentials are valid
+ if ($applet_ip &&
+ $master_applet->{port} &&
+ $gamename)
+ {
+ # add to database
+ $self->add_master_applet(
+ ip => $applet_ip,
+ port => $master_applet->{port},
+ gamename => $gamename,
+ );
+
+ #log
+ $self->log("add", "added applet $master_applet->{address}:$master_applet->{port} for $gamename");
+
+ } # else: insufficient info available
+ else {
+ $self->log("fail", "Could not add master applet: ".
+ ($applet_ip || "unknown ip"). ", ".
+ ($master_applet->{port} || "0"). ", ".
+ ($gamename || "game"). "."
+ );
+ }
+ } # end gamename
+ } # end master_applet
+
+ # reset added/updated time to last current time
+ $self->reset_master_applets();
+
+ # clear out the original variable, we don't use it anymore
+ $self->{master_applet} = ();
+
+ # report
+ $self->log("info", "Applet database successfully updated!");
+
+}
+
+################################################################################
+## There are three ways to load new masterservers to sync with.
+## 1: from the config file; address, port and beaconport are provided
+## 2: from a heartbeat; this automatically parses like all other servers
+## 3: from another sync request. Add if sufficient info is available
+################################################################################
+sub load_sync_masters {
+ my $self = shift;
+
+ # loop through config entries
+ foreach my $sync_host (@{$self->{sync_masters}}) {
+
+ # add them to database
+ $self->add_sync_master($sync_host);
+ }
+
+ # clear out the original variable, we don't use it anymore
+ $self->{sync_masters} = ();
+
+ # report
+ $self->log("info", "Sync server database successfully updated!");
+
+}
+
+################################################################################
+## Add a sync master according to cases 1 and 3.
+## Check for valid IP, port and/or beaconport
+################################################################################
+sub add_sync_master {
+ my ($self, $sync_host) = @_;
+
+ # sync_host contains
+ # address --> domain
+ # port --> tcp port
+ # beacon --> udp port
+
+ # resolve domain names
+ my $sync_ip = $self->host2ip($sync_host->{address});
+
+ # check if all credentials are valid
+ if ($sync_ip &&
+ $sync_host->{beacon} &&
+ $sync_host->{port})
+ {
+ # select sync master from serverlist
+ my $entry = $self->get_server(ip => $sync_ip,
+ port => $sync_host->{beacon})->[0];
+
+ # was found, update the entry
+ if (defined $entry) {
+ # update the serverlist with
+ my $sa = $self->update_server_list(
+ ip => $sync_ip,
+ port => $sync_host->{beacon},
+ hostport => $sync_host->{port},
+ gamename => "333networks",
+ );
+ }
+ # was not found, insert clean entry
+ else {
+ my $sa = $self->add_server_list(
+ ip => $sync_ip,
+ port => $sync_host->{beacon},
+ hostport => $sync_host->{port},
+ gamename => "333networks",
+ );
+
+ #log
+ $self->log("add", "added sync $sync_host->{address}:$sync_host->{port},$sync_host->{beacon}");
+ }
+ } # else: insufficient info available
+ else {
+ $self->log("fail", "Could not add sync master: ".
+ ($sync_ip || "ip"). ", ".
+ ($sync_host->{beacon} || "0"). ", ".
+ ($sync_host->{port} || "0"). "."
+ );
+ }
+}
+
+1;
diff --git a/lib/MasterServer/Core/Logging.pm b/lib/MasterServer/Core/Logging.pm
index e8631de..416a97f 100755
--- a/lib/MasterServer/Core/Logging.pm
+++ b/lib/MasterServer/Core/Logging.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Logging;
use strict;
@@ -6,6 +5,7 @@ use warnings;
use Switch;
use POSIX qw/strftime/;
use Exporter 'import';
+$|++;
our @EXPORT = qw| log error |;
@@ -46,41 +46,34 @@ sub error {
}
}
-
################################################################################
## Log to file and print to screen.
## args: $self, message_type, message
################################################################################
sub log {
my ($self, $type, $msg) = @_;
-
- # flush
- $| = 1;
-
- # parse time of log entry and prep for rotating log
- my $time = strftime('%Y-%m-%d %H:%M:%S',localtime);
- my $yearly = strftime('-%Y',localtime);
- my $monthly = strftime('-%Y-%m',localtime);
- my $weekly = strftime('-%Y-week%U',localtime);
- my $daily = strftime('-%Y-%m-%d',localtime);
-
+
# is the message suppressed in config?
return if (defined $type && $self->{suppress} =~ m/$type/i);
+
+ # parse time of log entry and prep for rotating log
+ my $time = strftime('%Y-%m-%d %H:%M:%S',localtime);
# determine filename
my $f = "MasterServer";
# rotate log filename according to config
- $f .= $daily if ($self->{log_rotate} =~ /^daily$/i );
- $f .= $weekly if ($self->{log_rotate} =~ /^weekly$/i );
- $f .= $monthly if ($self->{log_rotate} =~ /^monthly$/i );
- $f .= $yearly if ($self->{log_rotate} =~ /^yearly$/i );
+ $f .= strftime('-%Y-%m-%d',localtime) if ($self->{log_rotate} =~ /^daily$/i );
+ $f .= strftime('-%Y-week%U',localtime) if ($self->{log_rotate} =~ /^weekly$/i );
+ $f .= strftime('-%Y-%m',localtime) if ($self->{log_rotate} =~ /^monthly$/i);
+ $f .= strftime('-%Y',localtime) if ($self->{log_rotate} =~ /^yearly$/i );
$f .= ".log";
# put log filename together
my $logfile = $self->{log_dir}.((substr($self->{log_dir},-1) eq "/")?"":"/").$f;
- print "[$time] [$type] > $msg\n" if $self->{printlog};
+ # print to stdout if enabled
+ print "[$time]\t[$type]\t$msg\n" if $self->{printlog};
# temporarily disable the warnings-to-log, to avoid infinite recursion if
# this function throws a warning.
@@ -99,5 +92,4 @@ sub log {
$SIG{__WARN__} = $old;
}
-
1;
diff --git a/lib/MasterServer/Core/Schedulers.pm b/lib/MasterServer/Core/Schedulers.pm
index 97e45a5..cee4e5c 100755
--- a/lib/MasterServer/Core/Schedulers.pm
+++ b/lib/MasterServer/Core/Schedulers.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Schedulers;
use strict;
@@ -18,75 +17,90 @@ our @EXPORT = qw |
################################################################################
sub long_periodic_tasks {
my $self = shift;
- my $num = 0;
+ my $prev = 0;
return AnyEvent->timer (
- after => 300, # 5 minutes grace time
- interval => 1800, # execute every half hour
+ after => 30, # 30 seconds grace time
+ interval => 3600, # execute every hour
cb => sub {
- ## update Killing Floor stats
- $self->read_kfstats();
+ # update Killing Floor stats
+ $self->read_kfstats() if $self->{kfstats_enabled};
+
+ # delete old masterserver applets that have been unresponsive for a while now
+ $self->remove_unresponsive_applets() if (defined $self->{firstrun});
# time spacer
my $t = 0;
# clean out handles from the previous round (executed or not)
$self->{scope}->{sync} = ();
-
- ## Query Epic Games'-based UCC applets periodically to get an additional
- ## list of online UT, Unreal (or other) game servers.
- if ($self->{master_applet_enabled}) {
- for my $ms (@{$self->{master_applet}}) {
+
+ # Synchronize with all other 333networks masterservers that are uplinking,
+ # added by synchronization or manually listed.
+ if ($self->{sync_enabled}) {
+
+ # get serverlist
+ my $masterserverlist = $self->get_server(
+ updated => 3600,
+ gamename => "333networks",
+ );
- # add 3 second delay to spread network/server load
+ foreach my $ms (@{$masterserverlist}) {
+ # add 5 second delay to spread network/server load
$self->{scope}->{sync}->{$t} = AnyEvent->timer(
- after => 3*$t++,
- cb => sub{$self->query_applet($ms)}
- );
+ after => 5*$t++,
+ cb => sub{$self->sync_with_master($ms)}
+ ) if ($ms->{hostport} > 0);
}
}
+
+ # do NOT reset $t, keep padding time -- you should not have more than 300
+ # entries in applets/syncer in total anyway.
- # do NOT reset $t, keep padding time -- you should not have more than 600
- # entries in applets/syncer in total.
-
- ## Request the masterlist for selected or all games from other
- ## 333networks-based masterservers that uplinked to us and otherwise made
- ## our list (config, manual entry, etc)
- if ($self->{sync_enabled}) {
- foreach my $ms (values %{$self->masterserver_list()}) {
+ # Query Epic Games-based UCC applets periodically to get an additional
+ # list of online UT, Unreal and other game servers.
+ if ($self->{master_applet_enabled}) {
- # add 3 second delay to spread network/server load
+ # get applet list
+ my $appletlist = $self->get_masterserver_applets();
+
+ for my $ms (@{$appletlist}) {
+
+ # add 5 second delay to spread network/server load
$self->{scope}->{sync}->{$t} = AnyEvent->timer(
- after => 3*$t++,
- cb => sub{$self->sync_with_master($ms) if ($ms->{tcp} > 0)}
+ after => 5*$t++,
+ cb => sub{$self->query_applet($ms)}
);
}
}
#
- # Also very long-running tasks, like once per day:
+ # very long-running tasks, like database dumps
+ # interval from config
#
- if ($num++ >= 47) {
- # reset counter
- $num = 0;
-
- #
- # do database dump
- #
- my $time = strftime('%Y-%m-%d-%H-%M',localtime);
-
- # read db type from db login
- my @db_type = split(':', $self->{dblogin}->[0]);
- $db_type[2] =~ s/dbname=//;
+ my $curr = 0;
+ $curr = strftime('%d',localtime) if ($self->{dump_db} =~ /^daily$/i );
+ $curr = strftime('%U',localtime) if ($self->{dump_db} =~ /^weekly$/i );
+ $curr = strftime('%m',localtime) if ($self->{dump_db} =~ /^monthly$/i);
+ $curr = strftime('%Y',localtime) if ($self->{dump_db} =~ /^yearly$/i );
+
+ # on change, execute
+ if ($prev < $curr) {
- if ($db_type[1] eq "Pg") {
- # use pg_dump to dump Postgresql databases
- system("pg_dump $db_type[2] -U $self->{dblogin}->[1] > $self->{root}/data/dumps/$db_type[1]-$time.db");
- $self->log("dump", "Dumping database to /data/dumps/$db_type[1]-$time.db");
+ # skip on first run
+ if ($prev == 0) {
+ # update timer and loop
+ $prev = $curr;
+ return;
}
+
+ # dump db
+ $self->dump_database();
+
+ # update timekeeper
+ $prev = $curr;
}
-
},
);
}
@@ -102,22 +116,19 @@ sub short_periodic_tasks {
interval => 120,
cb => sub {
- ## update stats on direct beacons and total number of servers
+ # update stats on direct beacons and total number of servers
$self->update_stats();
- ## determine whether servers are still uplinking to us. If not, toggle.
+ # determine whether servers are still uplinking to us. If not, toggle.
$self->write_direct_beacons() if (defined $self->{firstrun});
- ## delete old servers from the "pending" list (except for the first run)
+ # delete old servers from the "pending" list (except for the first run)
$self->delete_old_pending() if (defined $self->{firstrun});
- ## uplink to other 333networks masterservers with heartbeats,
- ## that way we can index other masterservers too
+ # uplink to other 333networks masterservers with heartbeats, so other
+ # masterservers can find us too
$self->send_heartbeats();
-
- #
- # more short tasks?
- #
+
},
);
}
diff --git a/lib/MasterServer/Core/Secure.pm b/lib/MasterServer/Core/Secure.pm
index 51d1832..6d05f82 100755
--- a/lib/MasterServer/Core/Secure.pm
+++ b/lib/MasterServer/Core/Secure.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Secure;
use strict;
@@ -25,7 +24,7 @@ sub load_ciphers {
# first delete the old cipher database
$self->clear_ciphers();
- # start inserting ciphers (lots of 'em)
+ # start inserting ciphers (use transactions for slow systems)
$self->{dbh}->begin_work;
# iterate through the game list
@@ -36,10 +35,11 @@ sub load_ciphers {
$opt{gamename} = lc $_;
$opt{cipher} = $self->{game}->{$_}->{key};
$opt{description} = $self->{game}->{$_}->{label} || 'Unknown Game';
- $opt{default_qport} = $self->{game}->{$_}->{port} || 0;
+ $opt{default_qport} = $self->{game}->{$_}->{port} || 0;
# insert the game/cipher in the db or halt on error
if ($self->insert_cipher(%opt) < 0) {
+ # failure causes a fatal error and exits
$self->{dbh}->rollback;
$self->halt();
}
@@ -48,19 +48,14 @@ sub load_ciphers {
# commit
$self->{dbh}->commit;
$self->log("info", "Cipher database successfully updated!");
-
- # unload the game variables from masterserver memory
- $self->{game} = undef;
-
}
-
################################################################################
# generate a random string of 6 characters long for the \secure\ challenge
# returns string
################################################################################
sub secure_string {
- # spit out a random string, only uppercase characters
+ # generate a random string, only uppercase characters
my @c = ('A'..'Z');
my $s = "";
$s .= $c[rand @c] for 1..6;
@@ -82,23 +77,21 @@ sub compare_challenge {
# secure string too long? (because vulnerable in UE)
return 0 if (length $o{secure} > 16);
- # additional conditions to skip checking provided?
- $o{ignore} = "" unless $o{ignore};
-
# ignore this game if asked to do so
- if ($o{ignore} =~ m/$o{gamename}/i){
- $self->log("secure", "ignored beacon validation for $o{gamename}");
+ if ($self->{ignore_browser_key} =~ m/$o{gamename}/i){
+ $self->log("ignore", "ignored beacon validation for $o{gamename}");
return 1;
}
# enctype given?
$o{enctype} = 0 unless $o{enctype};
-
- # get cipher corresponding with the gamename
- my $cip = $self->get_game_props($o{gamename})->{cipher};
-
+
# calculate validate string
- my $val = get_validate_string($cip, $o{secure}, $o{enctype});
+ my $val = get_validate_string(
+ $self->get_game_props($o{gamename})->{cipher},
+ $o{secure},
+ $o{enctype}
+ );
# return whether or not they match
return ($val eq $o{validate});
@@ -136,33 +129,33 @@ sub validate_string {
# conversion and modification of the algorithm by Darkelarious, June 2014 with
# explicit, written permission of Luigi Auriemma.
#
+# use pre-built rotations for enctype
+# -- see GSMSALG 0.3.3 reference for copyright and more information
+my @enc_chars = ( qw |
+ 001 186 250 178 081 000 084 128 117 022 142 142 002 008 054 165
+ 045 005 013 022 082 007 180 034 140 233 009 214 185 038 000 004
+ 006 005 000 019 024 196 030 091 029 118 116 252 080 081 006 022
+ 000 081 040 000 004 010 041 120 081 000 001 017 082 022 006 074
+ 032 132 001 162 030 022 071 022 050 081 154 196 003 042 115 225
+ 045 079 024 075 147 076 015 057 010 000 004 192 018 012 154 094
+ 002 179 024 184 007 012 205 033 005 192 169 065 067 004 060 082
+ 117 236 152 128 029 008 002 029 088 132 001 078 059 106 083 122
+ 085 086 087 030 127 236 184 173 000 112 031 130 216 252 151 139
+ 240 131 254 014 118 003 190 057 041 119 048 224 043 255 183 158
+ 001 004 248 001 014 232 083 255 148 012 178 069 158 010 199 006
+ 024 001 100 176 003 152 001 235 002 176 001 180 018 073 007 031
+ 095 094 093 160 079 091 160 090 089 088 207 082 084 208 184 052
+ 002 252 014 066 041 184 218 000 186 177 240 018 253 035 174 182
+ 069 169 187 006 184 136 020 036 169 000 020 203 036 018 174 204
+ 087 086 238 253 008 048 217 253 139 062 010 132 070 250 119 184
+|);
+#
# args: game cipher, 6-char challenge string, encryption type
# returns: validate string (usually 8 characters long)
# !! requires cipher hash to be configured in config! (imported or otherwise)
################################################################################
sub get_validate_string {
my ($cipher_string, $secure_string, $enctype) = @_;
-
- # use pre-built rotations for enctype
- # -- see GSMSALG 0.3.3 reference for copyright and more information
- my @enc_chars = ( qw |
- 001 186 250 178 081 000 084 128 117 022 142 142 002 008 054 165
- 045 005 013 022 082 007 180 034 140 233 009 214 185 038 000 004
- 006 005 000 019 024 196 030 091 029 118 116 252 080 081 006 022
- 000 081 040 000 004 010 041 120 081 000 001 017 082 022 006 074
- 032 132 001 162 030 022 071 022 050 081 154 196 003 042 115 225
- 045 079 024 075 147 076 015 057 010 000 004 192 018 012 154 094
- 002 179 024 184 007 012 205 033 005 192 169 065 067 004 060 082
- 117 236 152 128 029 008 002 029 088 132 001 078 059 106 083 122
- 085 086 087 030 127 236 184 173 000 112 031 130 216 252 151 139
- 240 131 254 014 118 003 190 057 041 119 048 224 043 255 183 158
- 001 004 248 001 014 232 083 255 148 012 178 069 158 010 199 006
- 024 001 100 176 003 152 001 235 002 176 001 180 018 073 007 031
- 095 094 093 160 079 091 160 090 089 088 207 082 084 208 184 052
- 002 252 014 066 041 184 218 000 186 177 240 018 253 035 174 182
- 069 169 187 006 184 136 020 036 169 000 020 203 036 018 174 204
- 087 086 238 253 008 048 217 253 139 062 010 132 070 250 119 184
- |),
# convert to array of characters
my @cip = split "", $cipher_string;
diff --git a/lib/MasterServer/Core/Stats.pm b/lib/MasterServer/Core/Stats.pm
index 25044e8..8e9eb95 100755
--- a/lib/MasterServer/Core/Stats.pm
+++ b/lib/MasterServer/Core/Stats.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Stats;
use strict;
@@ -31,9 +30,8 @@ sub update_stats {
$self->write_stat(%opt);
}
- #done
+ # done
$self->log("stat", "Updated all game statistics.");
-
}
1;
diff --git a/lib/MasterServer/Core/Util.pm b/lib/MasterServer/Core/Util.pm
index 4f64fe1..682335c 100755
--- a/lib/MasterServer/Core/Util.pm
+++ b/lib/MasterServer/Core/Util.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Util;
use strict;
@@ -24,10 +23,10 @@ sub ip2country {
################################################################################
sub host2ip {
my ($self, $name) = @_;
- return inet_ntoa(inet_aton($name)) if $name;
+ my $unpack = inet_aton($name) if $name;
+ return inet_ntoa($unpack) if $unpack;
}
-
################################################################################
## Verify whether a given domain name or IP address and port are valid.
## returns 1/0 if valid/invalid ip + port. IPv4 ONLY!
@@ -36,8 +35,8 @@ sub valid_address {
my ($self, $a, $p) = @_;
# check if ip and port are in valid range
- my $val_addr = ($a =~ '\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b') if $a;
- my $val_port = (0 < $p && $p <= 65535) if $p;
+ 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/$_/)}
@@ -72,7 +71,7 @@ sub db_all {
}
################################################################################
-# sqlprint (TUWF):
+# sqlprint (TUWF, Yorhel):
# ? normal placeholder
# !l list of placeholders, expects arrayref
# !H list of SET-items, expects hashref or arrayref: format => (bind_value || \@bind_values)
diff --git a/lib/MasterServer/Core/Version.pm b/lib/MasterServer/Core/Version.pm
index 718b8c6..f87ea8d 100755
--- a/lib/MasterServer/Core/Version.pm
+++ b/lib/MasterServer/Core/Version.pm
@@ -1,4 +1,3 @@
-
package MasterServer::Core::Version;
use strict;
@@ -27,16 +26,16 @@ sub version {
#
# master type
- $self->{build_type} = "333networks Masterserver-Perl pre-release";
+ $self->{build_type} = "333networks Masterserver-Perl Multidb";
# version
- $self->{build_version} = "2.2.5";
+ $self->{build_version} = "2.3.0";
# short version for uplinks
$self->{short_version} = "MS-perl $self->{build_version}";
# date yyyy-mm-dd
- $self->{build_date} = "2016-11-19";
+ $self->{build_date} = "2017-05-13";
#author, email
$self->{build_author} = "Darkelarious, darkelarious\@333networks.com";