Newcomer1989 / TSN-Ranksystem

A PHP Bot that assigns time based server groups on TeamSpeak3.
https://ts-ranksystem.com
GNU General Public License v3.0
144 stars 60 forks source link

Winows - Bot öffnet mehrere QueryConnections #518

Closed Kamiikaze closed 6 years ago

Kamiikaze commented 6 years ago

Lasse den Bot über Windows Aufgabeplanung laufen: "C:\Program Files (x86)\Plesk\Additional\PleskPHP71\php.exe" -f "C:\Inetpub\vhosts\greenhell-gaming.de\httpdocs\tsrank\worker.php" check aber jedes mal wenn der Trigger läuft, wird ein neuer Bot gestartet. Auch wenn ich im TSrank-Ordner php worker.php check ausführe. (dabei kommt immer "Ungültiges Aliasverb") Die "pid" im Logs-Ordner ändert sich nur wenn ich alle Bots gekillt habe und das erste mal starte, danach starten die Bots weiter aber die pid ändert sich nicht und nach paar stunden habe ich um die 10 Query Clients verbunden. PHP --version => 7.1.19

Newcomer1989 commented 6 years ago

Der Bot fragt über wmic die Prozess-ID (=PID) ab. Hierfür ist zunächst eine Einrichtung erforderlich -> siehe Punkt 4 Wiki - Windows

Beim Starten des Bots wird dann der folgende wmic Befehl ausgeführt, um die PID zu erhalten. Deinen Beschreibungen nach scheint das noch zu funktionieren. wmic process WHERE "Name="php.exe" AND CommandLine LIKE "%bot.php%"" get ProcessId

Beim check Befehl wird dann natürlich ein anderer Befehl benutzt der gezielt auf die PID fragt. Wobei im folgenden PID durch die entsprechende ID zu ersetzen ist. wmic process where "Name="php.exe" and processid="PID"" get processid

An dieser Stelle muss vermutlich der Fehler entstehen, da sonst keine zusätzlichen Bots gestartet werden sollten.

Wichtig ist natürlich, dass der Prozess/Task, welcher den check Befehl startet die entsprechenden Rechte hat, den bereits gestarteten Bot (laufenden Prozess) überhaupt zu sehen. z.B. könnten hier entsprechende Berechtigungen fehlen oder unterschiedliche User das Problem verursachen.

Bitte die o.g. Befehl mit dem entsprechenden User nachstellen und die zurückgemeldeten Werte mit denen aus dem PID-File vergleichen.

Kamiikaze commented 6 years ago

wmic process WHERE "Name="php.exe" AND CommandLine LIKE "%bot.php%"" get ProcessId https://i.imgur.com/kQdlfC2.png

wmic process where "Name="php.exe" and processid="PID"" get processid https://i.imgur.com/hQ5hn6I.png

User gibt es nur den Administrator und dieser wird zum ausführen des Tasks benutzt. Sobald ich den check-befehl ausführe startet eine neue instanz mit neuer pid (hier 11032) aber im file bleibt diese gleich. https://i.imgur.com/PsJ39BR.png

Somit häufen sich die Bots dann an: https://i.imgur.com/XjcZu7b.png

Kamiikaze commented 6 years ago

In worker.php bei der function "checkProcess" wird wmic process where \"Name=\"php.exe\" and processid=\"".$pid."\"\" get processid 2>nul ausgeführt. wenn ich die pid eintrage und es ausführe bekomm ich die meldung: "Knoten - Win-7SM163QVH8B Fehler: Beschreibung = DIe Anfrage ist Ungültig" https://i.imgur.com/bujfOls.png

das problem sind so wie es aussieht die " bei $pid so exec("wmic process where processid=".$pid." get processid", $result); kann ich den bot auch wieder stoppen, bei "check" startet er auch keine weitere instanz mehr. Nach 5min hat der bot mich und andere nicht im verify channel gesehen aber nachdem ich mit zeit hinzugefügt habe über das addon war ich automatisch verbunden :o

Newcomer1989 commented 6 years ago

https://i.imgur.com/bujfOls.png

Das kann so natürlich nicht funktionieren, da die Backslashs zum escapen sind und für PHP benötigt werden, jedoch nicht bei einem manuellen Aufruf genutzt werden dürfen. Die Rückmeldung in diesem Fall ist also ein anderes Thema.

so exec("wmic process where processid=".$pid." get processid", $result);

Auf welche Code-Zeile beziehst du dich hier genau? Wenn ich es richtig sehe, hast du auch den check auf die PHP.exe entfernt. Wenn du diesen wieder aufnimmst, funktioniert es dann auch noch?

Kamiikaze commented 6 years ago

Hier mein worker.php funkzioniert und läuft nun seit gestern einwandfrei :D Habe nur die 2 Zeilen in "function checkProcess" geändert. ( https://pastebin.com/UyFHDSh4 ) Mit dem Check auf die php.exe bekomm ich wieder keine ausgabe oder den fehler https://i.imgur.com/mggxX1O.png wenn du zeit und lust hast können wir uns ja zusammen auf meinen server schalten und du schaust mal rüber :)

<?php
error_reporting(0);

require_once(__DIR__.'/other/config.php');
require_once(__DIR__.'/other/phpcommand.php');
$GLOBALS['exec'] = FALSE;
if($logpath == NULL) { $logpath = "./logs/"; }
$GLOBALS['logfile'] = $logpath.'ranksystem.log';

if (substr(php_uname(), 0, 7) == "Windows") {
    $GLOBALS['pidfile'] = __DIR__.'\logs\pid';
    $GLOBALS['autostart'] = __DIR__.'\logs\autostart_deactivated';
} else {
    $GLOBALS['pidfile'] = __DIR__.'/logs/pid';
    $GLOBALS['autostart'] = __DIR__.'/logs/autostart_deactivated';
}

function checkProcess($pid = null) {
    if (substr(php_uname(), 0, 7) == "Windows") {
        if(!empty($pid)) {
            //exec("wmic process where \"Name=\"php.exe\" and processid=\"".$pid."\"\" get processid 2>nul", $result);
            exec("wmic process where processid=".$pid." get processid", $result);
            if(isset($result[1]) && is_numeric($result[1])) {
                return TRUE;
            } else {
                return FALSE;
            }
        } else {
            if (file_exists($GLOBALS['pidfile'])) {
                $pid = str_replace(array("\r", "\n"), '', file_get_contents($GLOBALS['pidfile']));
                //exec("wmic process where \"Name=\"php.exe\" and processid=\"".$pid."\"\" get processid", $result);
                exec("wmic process where processid=".$pid." get processid", $result);
                if(isset($result[1]) && is_numeric($result[1])) {
                    return TRUE;
                } else {
                    return FALSE;
                }
            } else {
                return FALSE;
            }
        }
    } else {
        if(!empty($pid)) {
            $result = str_replace(array("\r", "\n"), '', shell_exec("ps ".$pid));
            if (strstr($result, $pid)) {
                return TRUE;
            } else {
                return FALSE;
            }
        } else {
            if (file_exists($GLOBALS['pidfile'])) {
                $check_pid = str_replace(array("\r", "\n"), '', file_get_contents($GLOBALS['pidfile']));
                $result = str_replace(array("\r", "\n"), '', shell_exec("ps ".$check_pid));
                if (strstr($result, $check_pid)) {
                    return TRUE;
                } else {
                    return FALSE;
                }
            } else {
                return FALSE;
            }
        }
    }
}

function start() {
    global $phpcommand;
    if(isset($_SERVER['USER']) && $_SERVER['USER'] == "root" || isset($_SERVER['USERNAME']) && $_SERVER['USERNAME'] == "administrator") {
        echo "\n !!!! Do not start the Ranksystem with root privileges !!!!\n\n";
        echo " Start Ranksystem Bot in 10 seconds...\n\n";
        sleep(10);
    }

    global $logpath;
    if(substr(sprintf('%o', fileperms($logpath)), -3, 1)!='7') {
        echo "\n !!!! Logs folder is not writable !!!!\n\n";
        echo " Cancel start request...\n\n";
        exit;
    }

    if (substr(php_uname(), 0, 7) == "Windows") {
        if (checkProcess() == FALSE) {
            echo "Starting the Ranksystem Bot.";
            try {
                $WshShell = new COM("WScript.Shell");
            } catch (Exception $e) {
                echo "\n Error due loading the PHP COM module (wrong server configuration!): ",$e->getMessage(),"\n";
            }
            try {
                $oExec = $WshShell->Run("cmd /C ".$phpcommand." ".__DIR__."\jobs\bot.php", 0, false);
            } catch (Exception $e) {
                echo "\n Error due starting Bot (exec command enabled?): ",$e->getMessage(),"\n";
            }
            try {
                exec("wmic process WHERE \"Name=\"php.exe\" AND CommandLine LIKE \"%bot.php%\"\" get ProcessId", $pid);
            } catch (Exception $e) {
                echo "\n Error due getting process list (wmic command enabled?): ",$e->getMessage(),"\n";
            }
            if(isset($pid[1]) && is_numeric($pid[1])) {
                exec("echo ".$pid[1]." > ".$GLOBALS['pidfile']);
                echo " [OK]\n";
                if (file_exists($GLOBALS['autostart'])) {
                    unlink($GLOBALS['autostart']);
                }
            } else {
                echo " [Failed]\n";
            }
        } else {
            echo "The Ranksystem is already running.\n";
        }
        $GLOBALS['exec'] = TRUE;
    } else {
        if (checkProcess() == FALSE) {
            echo "Starting the Ranksystem Bot.";
            exec($phpcommand." ".dirname(__FILE__)."/jobs/bot.php >/dev/null 2>&1 & echo $! > ".$GLOBALS['pidfile']);
            if (checkProcess() == FALSE) {
                echo " [Failed]\n";
            } else {
                echo " [OK]\n";
                if (file_exists($GLOBALS['autostart'])) {
                    unlink($GLOBALS['autostart']);
                }
            }
        } else {
            echo "The Ranksystem is already running.\n";
        }
        $GLOBALS['exec'] = TRUE;
    }
}

function stop() {
    if (substr(php_uname(), 0, 7) == "Windows") {
        if (checkProcess() == TRUE) {
            echo "Stopping the Ranksystem Bot.\n";
            $pid = str_replace(array("\r", "\n"), '', file_get_contents($GLOBALS['pidfile']));
            exec("del /F ".$GLOBALS['pidfile']);
            echo "Wait until Bot is down";
            $count_check=0;
            while (checkProcess($pid) == TRUE) {
                sleep(1);
                echo ".";
                $count_check ++;
                if($count_check > 10) {
                    exec("taskkill /F /PID ".$pid);
                    break;
                }
            }
            if (checkProcess($pid) == TRUE) {
                echo " [Failed]\n";
            } else {
                echo " [OK]\n";
                touch($GLOBALS['autostart']);
            }
        } else {
            echo "The Ranksystem seems not running.\n";
        }
        $GLOBALS['exec'] = TRUE;
    } else {
        if (checkProcess() == TRUE) {
            echo "Stopping the Ranksystem Bot.\n";
            $pid = str_replace(array("\r", "\n"), '', file_get_contents($GLOBALS['pidfile']));
            exec("rm -f ".$GLOBALS['pidfile']);
            echo "Wait until Bot is down";
            $count_check=0;
            while (checkProcess($pid) == TRUE) {
                sleep(1);
                echo ".";
                $count_check ++;
                if($count_check > 10) {
                    exec("kill -9 ".$pid);
                    break;
                }
            }
            if (checkProcess($pid) == TRUE) {
                echo " [Failed]\n";
            } else {
                echo " [OK]\n";
                touch($GLOBALS['autostart']);
            }
        } else {
            echo "The Ranksystem seems not running.\n";
        }
        $GLOBALS['exec'] = TRUE;
    }
}

function check() {
    if (checkProcess() == FALSE) {
        if (!file_exists($GLOBALS['autostart'])) {
            if (file_exists($GLOBALS['pidfile'])) {
                unlink($GLOBALS['pidfile']);
            }
            start();
        } else {
            echo "Starting the Ranksystem Bot. [Failed]\nAutostart is deactivated. Use start command instead.\n";
        }
    }
    $GLOBALS['exec'] = TRUE;
}

function restart() {
    stop();
    start();
    $GLOBALS['exec'] = TRUE;
}

function status() {
    if (checkProcess() == FALSE) {
        echo "The Ranksystem does not seem to run.\n";
    } else {
        echo "The Ranksystem seems to be running.\n";
    }
    $GLOBALS['exec'] = TRUE;
}

function help() {
    echo " Usage: php worker.php {start|stop|restart|check|status}\n\n",
          "\t* start   \t\t [start Ranksystem Bot]\n",
          "\t* stop    \t\t [stop Ranksystem Bot]\n",
          "\t* restart \t\t [restart Ranksystem Bot]\n",
          "\t* check   \t\t [check Ranksystem Bot is running; if not, start it; no output if all is ok]\n",
          "\t* status  \t\t [output status Ranksystem Bot]\n";
    $GLOBALS['exec'] = TRUE;
}

if (isset($_SERVER['argv'][1]) == 0) {
    help();
} else {
    $cmd = $_SERVER['argv'][1];
    if ($cmd == 'start')    start();
    if ($cmd == 'stop')     stop();
    if ($cmd == 'restart')  restart();
    if ($cmd == 'check')    check();
    if ($cmd == 'status')   status();
    if ($cmd == 'help')     help();

    if ($GLOBALS['exec'] == FALSE) echo " Error parameter '$cmd' not valid. Type \"php worker.php help\" to get a list of valid parameter.\n";
}
?>
Kamiikaze commented 6 years ago

Nun sind wir mit unserem RootServer zu einem anderen Hoster umgezogen. Habe dort alles auf standard zurückgesetzt und auch dort startet der Bot mehrmals mit dem Check parameter. Wenn ich meine Änderungen rein machen ist immer nur 1 query bot da. (So wie es sein soll^^) Aber dafür werden keine User im verify channel angezeigt :/

Newcomer1989 commented 6 years ago

Wir werden mit dem nächsten Update die worker.php etwas ändern. Ob es bei deiner vorgeschlagenen Änderung bleibt oder wir das noch etwas anpassen werden, werden unsere Tests ergeben. Gerne bei der nächsten Version noch einmal näher betrachten, ob es immer noch zu den genannten Problem kommt.

Newcomer1989 commented 6 years ago

Wir haben die worker.php nun an einigen Stellen angepasst.

Wäre super, wenn du es bei dir mal austesten könntest, ob es damit funktioniert und uns eine Rückmeldung gibst.

Hierfür einfach die folgende worker.php herunterladen und damit die vorhandene im Ranksystem Verzeichnis überschreiben.

Anschließend sollte sich das Ranksystem ohne Probleme über das Webinterface starten, stoppen und restarten lassen.

Kamiikaze commented 6 years ago

php worker.php start pid = 6904 task manager pid = 6904 Query Bots = 1

php worker.php check pid = 6904 task manager pid = 6904, 7900 Query Bots = 2

php worker.php check pid = 6904 task manager pid = 6904, 7900, 5712 Query Bots = 3

leider noch immer das problem

Newcomer1989 commented 6 years ago

php worker.php start php sworker.php check

Wo ist der Unterschied zwischen den beiden Scripten und warum werden unterschiedliche benutzt?

Kamiikaze commented 6 years ago

Sorry ist nur ein tippfehler..

Newcomer1989 commented 6 years ago

Wenn du gerade Zeit hättest, können wir uns das mal gemeinsam anschauen. Bin auf dem Public TS erreichbar (ts-n.net).

Newcomer1989 commented 6 years ago

Per Fernwartung konnte die neue worker.php erfolgreich getestet werden. Eine Auslieferung erfolgt mit Version 1.2.10.