Masterserver mods announse, ipv6, better curl errors
authorproller <proller@github.com>
Thu, 4 Jul 2013 15:39:26 +0000 (19:39 +0400)
committerproller <proller@github.com>
Fri, 12 Jul 2013 20:19:05 +0000 (00:19 +0400)
minetest.conf.example
src/client.cpp
src/convert_json.cpp
src/guiEngine.cpp
src/server.cpp
src/serverlist.cpp
src/serverlist.h
util/master/list.js
util/master/master.cgi
util/master/style.css

index 5b250296572a91091b1a7dc8e0f6a518d6859277..4e3fd4117043b54b613e47be80bc3b587d09b65b 100644 (file)
 #server_url = http://minetest.net
 # Automaticaly report to masterserver
 #server_announce = 0
+# Announce to this masterserver. if you want to announce your ipv6 address - use  serverlist_url = v6.servers.minetest.net
+#serverlist_url = servers.minetest.net
 # Default game (default when creating a new world)
 #default_game = minetest
 # World directory (everything in the world is stored here)
index 19105b504d7d375b84ca24597b3c9c6176410139..c458684f60ca5e3a4a65df41973eb3fb2cfe9fbd 100644 (file)
@@ -250,7 +250,7 @@ void * MediaFetchThread::Thread()
                        m_file_data.push_back(make_pair(i->name, data));
                } else {
                        m_failed.push_back(*i);
-                       infostream << "cURL request failed for " << i->name << std::endl;
+                       infostream << "cURL request failed for " << i->name << " (" << curl_easy_strerror(res) << ")"<< std::endl;
                }
                curl_easy_cleanup(curl);
        }
index 7a69071ef2f3064c031cb9567b53e946dcb29b42..9b704aca6deda55c231c40a669ff7eef5b5e6bb5 100644 (file)
@@ -59,7 +59,7 @@ Json::Value                 fetchJsonValue(const std::string url,
 
                res = curl_easy_perform(curl);
                if (res != CURLE_OK)
-                       errorstream<<"Jsonreader: "<< url <<" not found (internet connection?)"<<std::endl;
+                       errorstream<<"Jsonreader: "<< url <<" not found (" << curl_easy_strerror(res) << ")" <<std::endl;
                curl_easy_cleanup(curl);
        }
 
index f3b3a68456f69ccc339d67a2ee90da619b326e8a..2324dba16bcf7a1ff7e407db8648110eb86664b5 100644 (file)
@@ -533,7 +533,7 @@ bool GUIEngine::downloadFile(std::string url,std::string target) {
                        res = curl_easy_perform(curl);
                        if (res != CURLE_OK) {
                                errorstream << "File at url \"" << url
-                                       <<"\" not found (internet connection?)" <<std::endl;
+                                       <<"\" not found (" << curl_easy_strerror(res) << ")" <<std::endl;
                                retval = false;
                        }
                        fclose(targetfile);
index 60bf422f7fbba4d8422f98bc9fccb429326809a3..955858c70217f74c543946ef0517398459ede2d5 100644 (file)
@@ -1237,7 +1237,7 @@ void Server::AsyncRunStep()
                float &counter = m_masterserver_timer;
                if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
                {
-                       ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
+                       ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
                        counter = 0.01;
                }
                counter += dtime;
index 6a68e0eacc0ad31febfe82e859f6b459e248c0e4..7a374eb47179dbf3520a3774a21910ca8dd737bd 100644 (file)
@@ -194,34 +194,40 @@ std::string serializeJson(std::vector<ServerListSpec> serverlist)
 #if USE_CURL
 static size_t ServerAnnounceCallback(void *contents, size_t size, size_t nmemb, void *userp)
 {
-    return 0;
     //((std::string*)userp)->append((char*)contents, size * nmemb);
-    //return size * nmemb;
+    return size * nmemb;
 }
-void sendAnnounce(std::string action, u16 clients, double uptime, std::string gameid) {
+void sendAnnounce(std::string action, u16 clients, double uptime, std::string gameid, std::vector<ModSpec> m_mods) {
        Json::Value server;
        if (action.size())
                server["action"]        = action;
        server["port"] = g_settings->get("port");
-        if (action != "del") {
+       server["address"]       = g_settings->get("server_address");
+       if (action != "delete") {
                server["name"]          = g_settings->get("server_name");
                server["description"]   = g_settings->get("server_description");
-               server["address"]       = g_settings->get("server_address");
                server["version"]       = VERSION_STRING;
                server["url"]           = g_settings->get("server_url");
                server["creative"]      = g_settings->get("creative_mode");
                server["damage"]        = g_settings->get("enable_damage");
                server["dedicated"]     = g_settings->get("server_dedicated");
+               server["rollback"]      = g_settings->getBool("enable_rollback_recording");
                server["password"]      = g_settings->getBool("disallow_empty_password");
                server["pvp"]           = g_settings->getBool("enable_pvp");
                server["clients"]       = clients;
                server["clients_max"]   = g_settings->get("max_users");
                if (uptime >=1) server["uptime"] = (int)uptime;
                if (gameid!="") server["gameid"] = gameid;
-               
        }
-       if(server["action"] == "start")
+
+       if(server["action"] == "start") {
+               server["mods"] = Json::Value(Json::arrayValue);
+               for(std::vector<ModSpec>::iterator m = m_mods.begin(); m != m_mods.end(); m++) {
+                       server["mods"].append(m->name);
+               }
                actionstream << "announcing to " << g_settings->get("serverlist_url") << std::endl;
+       }
+
        Json::StyledWriter writer;
        CURL *curl;
        curl = curl_easy_init();
@@ -236,8 +242,8 @@ void sendAnnounce(std::string action, u16 clients, double uptime, std::string ga
                curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
                curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
                res = curl_easy_perform(curl);
-               //if (res != CURLE_OK)
-               //      errorstream<<"Serverlist at url "<<g_settings->get("serverlist_url")<<" not found (internet connection?)"<<std::endl;
+               if (res != CURLE_OK)
+                       errorstream<<"Serverlist at url "<<g_settings->get("serverlist_url")<<" error ("<<curl_easy_strerror(res)<<")"<<std::endl;
                curl_easy_cleanup(curl);
        }
 
index d01415c504c845496fdbb58214cd1ff559c5477d..365e86beb6e4242ba2110fc40429c6e8ccb34a50 100644 (file)
@@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include <iostream>
 #include "config.h"
+#include "mods.h"
 #include "json/json.h"
 
 #ifndef SERVERLIST_HEADER
@@ -39,7 +40,7 @@ namespace ServerList
        std::vector<ServerListSpec> deSerializeJson(std::string liststring);
        std::string serializeJson(std::vector<ServerListSpec>);
        #if USE_CURL
-       void sendAnnounce(std::string action = "", u16 clients = 0, double uptime = 0, std::string gameid = "");
+       void sendAnnounce(std::string action = "", u16 clients = 0, double uptime = 0, std::string gameid = "", std::vector<ModSpec> m_mods = std::vector<ModSpec>());
        #endif
 } //ServerList namespace
 
index 98f5ad490a6ff6b1a3ca7582c638b3a7ba77a0e1..c414a92b4c7d2bfc934f903a368a9d6cb6e4dc95 100644 (file)
@@ -45,17 +45,28 @@ function success(r) {
     for (var i = 0; i < r.list.length; ++i) {
         var s = r.list[i];
         if (!s) continue;
+        if (/:/.test(s.address)) s.address = '[' + s.address + ']';
         h += '<tr class="mts_row">';
         h += '<td class="mts_address">' + e(s.address) + (s.port != 30000 ? (':' + e(s.port)) : '') + '</td>';
         h += '<td class="mts_clients">' + e(s.clients) + (s.clients_max ? '/' + e(s.clients_max) : '') + (s.clients_top ? ', ' + s.clients_top : '') + '</td>';
-        h += '<td class="mts_version">' + e(s.version) + ' ' + e(s.gameid) + '</td>';
+        h += '<td class="mts_version">' + e(s.version) + ' ' + e(s.gameid);
+        if (s.mods && jQuery.isArray(s.mods)) {
+            h += '<div class="mts_mods">Mods:<br/>';
+            for (m in s.mods) {
+                h += s.mods[m] + '<br/>';
+            }
+            h += '</div>';
+        }
+
+        h += '</td>';
+
         h += '<td class="mts_url">';
         if (s.url) h += '<a href="' + e(s.url) + '">';
         h += e(s.name || s.url);
         if (s.url) h += '</a>';
         h += '</td>';
         h += '<td class="mts_description">' + e(s.description) + '</td>';
-        h += '<td class="mts_flags">' + e(s.password ? 'Pwd ' : '') + (s.creative ? 'Cre ' : '') + (s.damage ? 'Dmg ' : '') + (s.pvp ? 'Pvp ' : '') + (s.dedicated ? 'Ded ' : '') + '</td>';
+        h += '<td class="mts_flags">' + e(s.password ? 'Pwd ' : '') + (s.creative ? 'Cre ' : '') + (s.damage ? 'Dmg ' : '') + (s.pvp ? 'Pvp ' : '') + (s.dedicated ? 'Ded ' : '') + (s.rollback ? 'Rol ' : '') + '</td>';
         if (!s.start || s.start < 0) s.start = 0;
         h += '<td class="mts_time">' + (s.uptime ? human_time(s.uptime, 1) : s.start ? human_time(s.start) : '') + '</td>';
         h += '<td class="mts_ping">' + (s.ping ? parseFloat(s.ping).toFixed(3) * 1000 : '') + '</td>';
index 0e456ed0cace4ee77216b27ffceb0cdf8376294a..e283fe3a2f28717d885c753b533810495ac77e7a 100755 (executable)
@@ -4,7 +4,7 @@
 install:
  cpan JSON JSON::XS
  touch list_full list
- chmod a+rw list_full list
+ chmod a+rw list_full list log.log
 
 freebsd:
  www/fcgiwrap www/nginx
@@ -50,10 +50,18 @@ use warnings "NONFATAL" => "all";
 no warnings qw(uninitialized);
 use utf8;
 use Socket;
+BEGIN {
+    if ($Socket::VERSION ge '2.008') {
+        eval qq{use Socket qw(getaddrinfo getnameinfo NI_NUMERICHOST NIx_NOSERV)}; # >5.16
+    } else {
+        eval qq{use Socket6 qw(getaddrinfo getnameinfo NI_NUMERICHOST NIx_NOSERV)}; # <5.16
+    }
+};
 use Time::HiRes qw(time sleep);
-use IO::Socket::INET;
+use IO::Socket::IP;
 use JSON;
 use Net::Ping;
+#use Data::Dumper;
 our $root_path;
 ($ENV{'SCRIPT_FILENAME'} || $0) =~ m|^(.+)[/\\].+?$|;    #v0w
 $root_path = $1 . '/' if $1;
@@ -63,6 +71,7 @@ our %config = (
     #debug        => 1,
     list_full    => $root_path . 'list_full',
     list_pub     => $root_path . 'list',
+    log          => $root_path . 'log.log',
     time_purge   => 86400 * 30,
     time_alive   => 650,
     source_check => 1,
@@ -109,6 +118,12 @@ sub file_rewrite(;$@) {
     print $fh @_;
 }
 
+sub printlog(;@) {
+    #local $_ = shift;
+    return unless open my $fh, '>>', $config{log};
+    print $fh (join ' ', @_), "\n";
+}
+
 sub file_read ($) {
     open my $f, '<', $_[0] or return;
     local $/ = undef;
@@ -120,7 +135,7 @@ sub file_read ($) {
 sub read_json {
     my $ret = {};
     eval { $ret = JSON->new->utf8->relaxed(1)->decode(${ref $_[0] ? $_[0] : file_read($_[0]) or \''} || '{}'); };    #'mc
-    warn "json error [$@] on [", ${ref $_[0] ? $_[0] : \$_[0]}, "]" if $@;
+    printlog "json error [$@] on [", ${ref $_[0] ? $_[0] : \$_[0]}, "]" if $@;
     $ret;
 }
 
@@ -133,16 +148,6 @@ sub printu (@) {
     }
 }
 
-sub name_to_ip_noc($) {
-    my ($name) = @_;
-    unless ($name =~ /^\d+\.\d+\.\d+\.\d+$/) {
-        local $_ = (gethostbyname($name))[4];
-        return ($name, 1) unless length($_) == 4;
-        $name = inet_ntoa($_);
-    }
-    return $name;
-}
-
 sub float {
     return ($_[0] < 8 and $_[0] - int($_[0]))
       ? sprintf('%.' . ($_[0] < 1 ? 3 : ($_[0] < 3 ? 2 : 1)) . 'f', $_[0])
@@ -152,11 +157,11 @@ sub float {
 
 sub mineping ($$) {
     my ($addr, $port) = @_;
-    warn "mineping($addr, $port)" if $config{debug};
+    printlog "mineping($addr, $port)" if $config{debug};
     my $data;
     my $time = time;
     eval {
-        my $socket = IO::Socket::INET->new(
+        my $socket = IO::Socket::IP->new(
             'PeerAddr' => $addr,
             'PeerPort' => $port,
             'Proto'    => 'udp',
@@ -171,7 +176,7 @@ sub mineping ($$) {
     } or return 0;
     return 0 unless length $data;
     $time = float(time - $time);
-    warn "recvd: ", length $data, " [$time]" if $config{debug};
+    printlog "recvd: ", length $data, " [$time]" if $config{debug};
     return $time;
 }
 
@@ -189,18 +194,22 @@ sub request (;$) {
         if (%$param) {
             s/^false$// for values %$param;
             $param->{ip} = $r->{REMOTE_ADDR};
+            $param->{ip} =~ s/^::ffff://;
             for (@{$config{blacklist}}) {
                 return if $param->{ip} ~~ $_;
             }
             $param->{address} ||= $param->{ip};
-            if ($config{source_check} and name_to_ip_noc($param->{address}) ne $param->{ip} and !($param->{ip} ~~ $config{trusted})) {
-                warn("bad address [$param->{address}] ne [$param->{ip}]") if $config{debug};
-                return;
+            if ($config{source_check}) {
+                (my $err, local @_) = getaddrinfo($param->{address});
+                my $addrs = [ map{(getnameinfo($_->{addr}, NI_NUMERICHOST, NIx_NOSERV))[1]} @_];
+                if (!($param->{ip} ~~ $addrs) and !($param->{ip} ~~ $config{trusted})) {
+                    printlog("bad address (", @$addrs, ")[$param->{address}] ne [$param->{ip}] [$err]") if $config{debug};
+                    return;
+                }
             }
             $param->{port} ||= 30000;
             $param->{key} = "$param->{ip}:$param->{port}";
             $param->{off} = time if $param->{action} ~~ 'delete';
-
             if ($config{ping} and $param->{action} ne 'delete') {
                 if ($config{mineping}) {
                     $param->{ping} = mineping($param->{ip}, $param->{port});
@@ -209,15 +218,15 @@ sub request (;$) {
                     $ping->service_check(0);
                     my ($pingret, $duration, $ip) = $ping->ping($param->{address});
                     if ($ip ne $param->{ip} and !($param->{ip} ~~ $config{trusted})) {
-                        warn "strange ping ip [$ip] != [$param->{ip}]" if $config{debug};
+                        printlog "strange ping ip [$ip] != [$param->{ip}]" if $config{debug};
                         return if $config{source_check} and !($param->{ip} ~~ $config{trusted});
                     }
                     $param->{ping} = $duration if $pingret;
-                    warn " PING t=$config{ping_timeout}, $param->{address}:$param->{port} = ( $pingret, $duration, $ip )" if $config{debug};
+                    printlog " PING t=$config{ping_timeout}, $param->{address}:$param->{port} = ( $pingret, $duration, $ip )" if $config{debug};
                 }
             }
             my $list = read_json($config{list_full}) || {};
-            warn "readed[$config{list_full}] list size=", scalar @{$list->{list}};
+            printlog "readed[$config{list_full}] list size=", scalar @{$list->{list}};
             my $listk = {map { $_->{key} => $_ } @{$list->{list}}};
             my $old = $listk->{$param->{key}};
             $param->{time} = $old->{time} if $param->{off};
@@ -227,18 +236,20 @@ sub request (;$) {
             $param->{first} ||= $old->{first} || $old->{time} || $param->{time};
             $param->{clients_top} = $old->{clients_top} if $old->{clients_top} > $param->{clients};
             $param->{clients_top} ||= $param->{clients} || 0;
+            $param->{mods} ||= $old->{mods};
             delete $param->{action};
             $listk->{$param->{key}} = $param;
+            #printlog Dumper $param;
             $list->{list} = [grep { $_->{time} > time - $config{time_purge} } values %$listk];
             file_rewrite($config{list_full}, JSON->new->encode($list));
-            warn "writed[$config{list_full}] list size=", scalar @{$list->{list}};
+            printlog "writed[$config{list_full}] list size=", scalar @{$list->{list}} if $config{debug};
             $list->{list} = [
                 sort { $b->{clients} <=> $a->{clients} || $a->{start} <=> $b->{start} }
                   grep { $_->{time} > time - $config{time_alive} and !$_->{off} and (!$config{ping} or !$config{pingable} or $_->{ping}) }
                   @{$list->{list}}
             ];
             file_rewrite($config{list_pub}, JSON->new->encode($list));
-            warn "writed[$config{list_pub}] list size=", scalar @{$list->{list}};
+            printlog "writed[$config{list_pub}] list size=", scalar @{$list->{list}} if $config{debug};
         }
     };
     return [200, ["Content-type", "application/json"], [JSON->new->encode({})]], $after;
index 638b51f80891259aba98415b76b59c48fa19b5ed..a8379404112287f64d71e1a85ee754034bf4e733 100644 (file)
@@ -11,4 +11,8 @@ td, th {
 
 div#table table {
   width: 100%;
-}
\ No newline at end of file
+}
+
+.mts_mods {visibility: hidden; border:gray solid 1px; position:absolute; z-index:100; background-color:white; padding:.5em;}
+.mts_version:hover .mts_mods {visibility: visible;}
+.mts_version {text-decoration:underline; text-decoration-style:dashed;}
\ No newline at end of file