Commit 3d6200d5 authored by Eric - kg6wxc's avatar Eric - kg6wxc
Browse files

Merge branch 'newPollingScripts' into 'master'

New Polling script!

Closes #19, #12, and #10

See merge request !10
parents df604384 5bf83196
#!/usr/bin/env php
<?php
/*************************************************************************************
* get-map-info script v4 by kg6wxc\eric satterlee kg6wxc@gmail.com
* March 2019
* Licensed under GPLv3 or later
* This script is the heart of kg6wxcs' mesh map system.
* bug fixes, improvements and corrections are welcomed!
*
* One Script to rule them all!!
*
* see CHANGELOG.md for notes
**************************************************************************************/
/******
* This file is part of the Mesh Mapping System.
* The Mesh Mapping System is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Mesh Mapping System is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with The Mesh Mapping System. If not, see <http://www.gnu.org/licenses/>.
******/
if (PHP_SAPI !== 'cli') {
$file = basename($_SERVER['PHP_SELF']);
exit("<style>html{text-align: center;}p{display: inline;}</style>
<br><strong>This script ($file) should only be run from the
$file = basename($_SERVER['PHP_SELF']);
exit("<style>html{text-align: center;}p{display: inline;}</style>
<br><strong>This script ($file) should only be run from the
<p style='color: red;'>command line</p>!</strong>
<br>exiting...");
}
$mtimeStart = microtime(true);
/*************************************************************************************
* get-map-info script v3 by kg6wxc\eric satterlee kg6wxc@gmail.com
* Licensed under GPLv3 or later
* This script is the heart of kg6wxcs' mesh map system.
* bug fixes, improvements and corrections are welcomed!
*
* One Script to rule them all!!
*
* see CHANGELOG.md for notes
**************************************************************************************/
/******
* This file is part of the Mesh Mapping System.
* The Mesh Mapping System is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Mesh Mapping System is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with The Mesh Mapping System. If not, see <http://www.gnu.org/licenses/>.
******/
//Increase PHP memory limit to 128M (you may need more if you are connected to a "Mega Mesh" :) )
//this should be moved to the ini file maybe
ini_set('memory_limit', '128M');
/***********************************************************************
*DO NOT CHANGE ANYTHING BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING!!!!
************************************************************************/
$INCLUDE_DIR = "..";
//check for users user-settings.ini file and use it if it exists
......@@ -113,6 +112,18 @@ if ($TEST_MODE_NO_SQL) {
$getNodeInfo = 0;
}
//output error messages only in the cron job
//if your system has an MTA installed you should get local emails from
//this script if there are errors, you can turn this on or off in the ini file.
//(not quite done yet)
$errOut = "0";
if(isset($GLOBALS['USER_SETTINGS']['errorsInCron'])) {
$errOut = $GLOBALS['USER_SETTINGS']['errorsInCron'];
}else {
$errOut = "0";
}
//(WiP)checks for some things we need to run
//(currently only really checks for the mysqli php extension
wxc_checkConfigs();
......@@ -130,95 +141,94 @@ $sql_db_tbl_node = $USER_SETTINGS['sql_db_tbl_node'];
$sql_db_tbl_topo = $USER_SETTINGS['sql_db_tbl_topo'];
if ($do_sql) {
//an sql connection that we can reuse...
//$sql_connection = wxc_connectToMySQL();
wxc_connectToMySQL();
//check for new or changed database items (tables, columns,etc)
wxc_checkDB();
//an sql connection that we can reuse...
//$sql_connection = wxc_connectToMySQL();
wxc_connectToMySQL();
//check for new or changed database items (tables, columns,etc)
wxc_checkDB();
}else {
if ($TEST_MODE_NO_SQL) {
wxc_echoWithColor("SQL Server access disabled!", "red");
echo "\n";
}
if ($TEST_MODE_NO_SQL) {
wxc_echoWithColor("SQL Server access disabled!", "red");
echo "\n";
}
}
//This controls when certain parts of the script run.
//We check the DB for the time we last checked and only run if we need to.
//intervals are now controled via the ini file.
//thanks K6GSE!
//intervals are now controled via the ini file thanks to K6GSE!
if ($do_sql) {
//if $do_sql is set to 1, check when we last polled all the known nodes, if it was more than the interval set the variable to 1
$lastRunGetNodeInfo = wxc_scriptGetLastDateTime("NODEINFO", "node_info");
if ($lastRunGetNodeInfo) {
if ($USER_SETTINGS['node_polling_interval'] > 0) {
$intervalNODE = date_diff($lastRunGetNodeInfo, $currentTime);
$intervalNodeInMinutes = $intervalNODE->days * 24 * 60;
$intervalNodeInMinutes += $intervalNODE->h * 60;
$intervalNodeInMinutes += $intervalNODE->i;
if ($intervalNodeInMinutes >= intval($USER_SETTINGS['node_polling_interval'])) {
if ($TEST_MODE_WITH_SQL) {
echo "It has been " . $USER_SETTINGS['node_polling_interval'] . " or more minutes since this script polled all the nodes\n";
echo "Set to poll nodes.\n";
}
$getNodeInfo = 1;
}
}
}else {
//probably never run before, lets get some data!!
echo "Set to poll nodes.\n";
$getNodeInfo = 1;
}
//if $do_sql is set to 1, check when we last got link info, if it was more than the interval set the variable to 1
$lastRunGetLinkInfo = wxc_scriptGetLastDateTime("LINKINFO", "topology");
if($lastRunGetLinkInfo) {
if ($USER_SETTINGS['link_update_interval'] > 0) {
$intervalLINK = date_diff($lastRunGetLinkInfo, $currentTime);
if ($intervalLINK->i >= intval($USER_SETTINGS['link_update_interval'])) {
if ($TEST_MODE_WITH_SQL) {
echo "It has been " . $USER_SETTINGS['link_update_interval'] . " or more minutes since this script got the link info\n";
echo "Set to get network linking info.\n\n";
}
$getLinkInfo = 1;
}
}
}else {
//probably never run before, let's get some data!
echo "Set to get network linking info.\n\n";
$getLinkInfo = 1;
}
//if $do_sql is set to 1, check when we last polled all the known nodes, if it was more than the interval set the variable to 1
$lastRunGetNodeInfo = wxc_scriptGetLastDateTime("NODEINFO", "node_info");
if ($lastRunGetNodeInfo) {
if ($USER_SETTINGS['node_polling_interval'] > 0) {
$intervalNODE = date_diff($lastRunGetNodeInfo, $currentTime);
$intervalNodeInMinutes = $intervalNODE->days * 24 * 60;
$intervalNodeInMinutes += $intervalNODE->h * 60;
$intervalNodeInMinutes += $intervalNODE->i;
if ($intervalNodeInMinutes >= intval($USER_SETTINGS['node_polling_interval'])) {
if ($TEST_MODE_WITH_SQL) {
echo "It has been " . $USER_SETTINGS['node_polling_interval'] . " or more minutes since this script polled all the nodes\n";
echo "Set to poll nodes.\n";
}
$getNodeInfo = 1;
}
}
}else {
//probably never run before, lets get some data!!
echo "Set to poll nodes.\n";
$getNodeInfo = 1;
}
//if $do_sql is set to 1, check when we last got link info, if it was more than the interval set the variable to 1
$lastRunGetLinkInfo = wxc_scriptGetLastDateTime("LINKINFO", "topology");
if($lastRunGetLinkInfo) {
if ($USER_SETTINGS['link_update_interval'] > 0) {
$intervalLINK = date_diff($lastRunGetLinkInfo, $currentTime);
if ($intervalLINK->i >= intval($USER_SETTINGS['link_update_interval'])) {
if ($TEST_MODE_WITH_SQL) {
echo "It has been " . $USER_SETTINGS['link_update_interval'] . " or more minutes since this script got the link info\n";
echo "Set to get network linking info.\n\n";
}
$getLinkInfo = 1;
}
}
}else {
//probably never run before, let's get some data!
echo "Set to get network linking info.\n\n";
$getLinkInfo = 1;
}
}
//check the database to see if we are already polling nodes
//this trys to prevent 2 polling runs at once
//it does nothing in "--test-mode-no-sql"
if ($do_sql) {
$currently_polling_nodes = wxc_getMySql("SELECT script_last_run, currently_running from map_info WHERE id = 'NODEINFO'");
if (is_null($currently_polling_nodes['currently_running'])) {
$currently_polling_nodes['currently_running'] = 0;
$getNodeInfo = 1;
}elseif ($currently_polling_nodes['currently_running'] == 1) {
$getNodeInfo = 0;
}
//hopefully catch a stalled polling run after 3 * node_polling_interval has expired.
//something may have gone wonky and the node polling run never completed and never had a chance
//to unset the "currently_running" bit in the DB,
//this *should* catch that and and just run the node polling again
if ($currently_polling_nodes['currently_running'] == 1 && $intervalNodeInMinutes >= intval($USER_SETTINGS['node_polling_interval']) * 3) {
$currently_polling_nodes['currently_running'] = 0;
$getNodeInfo = 1;
}
$currently_polling_nodes = wxc_getMySql("SELECT script_last_run, currently_running from map_info WHERE id = 'NODEINFO'");
if (is_null($currently_polling_nodes['currently_running'])) {
$currently_polling_nodes['currently_running'] = 0;
$getNodeInfo = 1;
}elseif ($currently_polling_nodes['currently_running'] == 1) {
$getNodeInfo = 0;
}
//hopefully catch a stalled polling run after 3 * node_polling_interval has expired.
//something may have gone wonky and the node polling run never completed and never had a chance
//to unset the "currently_running" bit in the DB,
//this *should* catch that and and just run the node polling again
if ($currently_polling_nodes['currently_running'] == 1 && $intervalNodeInMinutes >= intval($USER_SETTINGS['node_polling_interval']) * 3) {
$currently_polling_nodes['currently_running'] = 0;
$getNodeInfo = 1;
}
}
//check for old outdated node info (intervals will be set in the ini file)
//check for old outdated node info (intervals are set in the ini file)
$do_expire = $USER_SETTINGS['expire_old_nodes'];
if ($do_sql && $do_expire) {
wxc_checkOldNodes();
wxc_checkOldNodes();
}
if ($do_sql) {
wxc_removeIgnoredNodes();
wxc_removeIgnoredNodes();
}
$node = "";
if ($getNodeInfo) {
//this section is what goes out to each node on the mesh and asks for it's info
//this is really the heart of the mapping system, without this (and the sysinfo.json file),
......@@ -232,584 +242,530 @@ if ($getNodeInfo) {
$meshNodes = wxc_netcat($USER_SETTINGS['localnode'], "2004", null, "ipOnly");
if ($meshNodes) {
/* TESTING IDEA */
/*
$ipAddrArray = explode("\n", $meshNodes);
$ipAddrArrayChunks = array_chunk($ipAddrArray, $USER_SETTINGS['numParallelThreads']);
foreach($ipAddrArrayChunks as $chunk => $ipList) {
foreach($ipList as $ipAddr) {
//echo "";
}
}
foreach($ipAddrArray as $ipAddr) {
//echo "";
}
*/
/* END TESTING */
//
//parallel polling will have to at least start here
//going to have to break the IP list up into sections
//or create some kind of "container" that only allow so many to run at a time...
//
foreach (preg_split("/((\r?\n)|(\r\r?))/", $meshNodes) as $line) {
list ($ipAddr) = explode("\n", $line);
//check for nodes that we know will not have the info we are going to request and skip them
if ($do_sql) {
if (wxc_getMySql("SELECT ip FROM hosts_ignore WHERE ip = '$ipAddr'")) {
continue;
}
}
//copy to new var name (I dont feel like editing it all right now)
$nodeName = $ipAddr;
if ($USER_SETTINGS['node_polling_parallel']) {
shell_exec("php $INCLUDE_DIR/scripts/parallel_node_polling.php $ipAddr $do_sql 0 > /dev/null 2>/dev/null &");
//for($count = 1; $count <= 20; $count++) {
// $ipAddrList .= $ipAddr . "\n";
//}
// $parallel_pids = array();
//$parallel_pids[] = trim(shell_exec("php $INCLUDE_DIR/scripts/parallel_node_polling.php $ipAddr $do_sql 0 > /dev/null 2>/dev/null & echo $!"));
// $parallel_pids[] = trim(shell_exec("php $INCLUDE_DIR/scripts/parallel_node_polling.php $ipAddr $do_sql 0 > /dev/null 2>/dev/null & echo $!"));
//$parallel_pids[] = shell_exec("php $INCLUDE_DIR/scripts/parallel_node_polling.php $ipAddr $do_sql 0 > /dev/null & echo $!");
//var_dump($parallel_pids);
}else {
//get the sysinfo.json file from the node being polled.
$sysinfoJson = @file_get_contents("http://$ipAddr:8080/cgi-bin/sysinfo.json?services_local=1"); //get the .json file
list ($ipAddr) = explode("\n", $line);
//check if we got anything back, if not, try to tell why.
if($sysinfoJson === FALSE) {
$error = error_get_last();
wxc_checkErrorMessage($error, $nodeName);
//just skip to the next IP since there was an error
continue;
}else {
//node is there, get all the info we can
//get all the data from the json file and decode it
$result = json_decode($sysinfoJson,true);
//if there's nothing really there just skip to the next IP
if (!$result || empty($result)) {
//$host = wxc_resolveIP($ipAddr);
if($testNodePolling) {
wxc_echoWithColor("The json file is empty for node: " . $ipAddr . " " . wxc_resolveIP($ipAddr) . "\n", "red");
echo "\n";
}
//check for nodes that we know will not have the info we are going to request and skip them
if ($do_sql) {
if (wxc_getMySql("SELECT ip FROM hosts_ignore WHERE ip = '$ipAddr'")) {
continue;
}
//is RF enabled? (default to "on")
$meshRF = "on";
//pull out API version first
//some user-created json files leave out the api_version section
//so lets set a default
if (isset($result['api_version'])) {
$api_version = $result['api_version'];
}else {
//just make it 0.0.0 by default, it will always fail a compare_version then.
$api_version = "0.0.0";
}
//let's see what node we are dealing with
//sometimes this might be blank, catch it
if (version_compare($api_version, "1.5", "=")) {
if (isset($result['node_details']['node'])) {
$node = $result['node_details']['node'];
}else {
$node = $result['node'];
}
if (isset($result['meshrf']['status'])) {
if ($result['meshrf']['status'] == "off") {
$meshRF = "off";
}
}
}else {
$node = $result['node'];
}
//check API version first!
if (version_compare($api_version, "1.5", "=")) {
if (isset($result['location']['lat'])) {
$lat = $result['location']['lat'];
}else {
$lat = $result['lat'];
}
}else {
$lat = $result['lat'];
}
if (version_compare($api_version, "1.5", "=")) {
if (isset($result['location']['lon'])) {
$lon = $result['location']['lon'];
}else {
$lon = $result['lon'];
}
}else {
$lon = $result['lon'];
}
}
//copy to new var name (I dont feel like editing it all right now)
$nodeName = $ipAddr;
if ($USER_SETTINGS['node_polling_parallel']) {
//if it's nothing other than the node name, it's some other device
//or something else entirely...
//people hack things onto the mesh all the time
//
//kg6wxc is *not* guilty of such things... :)
//
//just a few checks for nothing usually catches it.
//it probably wont actually be this way in the end
//newer PHP supports threads
//***NOTE*** this might not be needed any more
if ($node && $lat == "" && $lon == "" && $result['api_version'] == "") {
continue;
}
//disabled for now
//shell_exec("php $INCLUDE_DIR/scripts/parallel_node_polling.php $ipAddr $do_sql 0 > /dev/null 2>/dev/null &");
//this only seems to affect some nodes.
//if lat || lon is blank, make it "0"
//this was sometimes screwing up the SQL writing function
//but not always of course.
if (empty($lat)) {
//if ($result['lat'] == "") {
$lat = 0.0;
}
//else {
// $lat = $result['lat;
//}
if (empty($lon)) {
//if ($result['lon'] == "") {
$lon = 0.0;
}
//else {
// $lon = $result['lon'];
//}
}else {
//save json data to some variables
//probably don't really need to do this, but it is what it is for now...
//get sysinfo.json fron node
//this is the heart of the mapping system
$sysinfoJson = @file_get_contents("http://$ipAddr:8080/cgi-bin/sysinfo.json?services_local=1");
//check for new sysinfo.json API
if (version_compare($api_version, "1.5", ">=")) {
if (isset($result['meshrf']['chanbw'])) {
$chanbw = $result['meshrf']['chanbw'];
}
else {
$chanbw = "0";
}
if (isset($result['meshrf']['status'])) {
if ($result['meshrf']['status'] == "off") {
$meshRF = "off";
$ssid = "NONE";
}
}else {
$ssid = $result['meshrf']['ssid'];
}
if ($meshRF == "off") {
$channel = "NONE";
}else {
$channel = $result['meshrf']['channel'];
}
$board_id = $result['node_details']['board_id'];
$firmware_version = $result['node_details']['firmware_version'];
$model = $result['node_details']['model'];
$firmware_mfg = $result['node_details']['firmware_mfg'];
$tunnel_installed = $result['tunnels']['tunnel_installed'];
$active_tunnel_count = $result['tunnels']['active_tunnel_count'];
if (isset($result['location']['grid_square'])) {
$grid_square = $result['location']['grid_square'];
}
else {
$grid_square = $result['grid_square'];
}
if($sysinfoJson === FALSE) {
$error = error_get_last();
wxc_checkErrorMessage($error, $nodeName);
//just skip to the next IP since there was an error
continue;
}else {
if (isset($result['chanbw'])) {
$chanbw = $result['chanbw'];
}
else {
$chanbw = "0";
}
if (isset($result['ssid'])) {
$ssid = $result['ssid'];
}else {
$ssid = "None";
}
if (isset($result['channel'])) {
$channel = $result['channel'];
}else {
$channel = "N/A";
}
if (isset($result['board_id'])) {
$board_id = $result['board_id'];
}
if (isset($result['firmware_version'])) {
$firmware_version = $result['firmware_version'];
}
if (isset($result['model'])) {
$model = $result['model'];
}
if (isset($result['firmware_mfg'])) {
$firmware_mfg = $result['firmware_mfg'];
}
if (isset($result['tunnel_installed'])) {
$tunnel_installed = $result['tunnel_installed'];
}
if (isset($result['active_tunnel_count'])) {
$active_tunnel_count = $result['active_tunnel_count'];
}
if (isset($result['grid_square'])) {
$grid_square = $result['grid_square'];
}
//get all the data from the json file and decode it
//remove any "funny" characters from the sysinfo.json string *BEFORE* it gets decoded
//these mainly occur when people get fancy with the description field
//use html name codes! do not use the hex codes!
$sysinfoJson = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $sysinfoJson);
$result = json_decode($sysinfoJson,true);
//catch some weird ones just in case...
//If you make a custom json file, try to make sure you conform to the AREDN api_versions.
//if not, this might catch it... maybe... we'll see.
if (isset($result['node_details']['board_id'])) {
$board_id = $result['node_details']['board_id'];
}
if (isset($result['node_details']['firmware_version'])) {
$firmware_version = $result['node_details']['firmware_version'];
}
if (isset($result['node_details']['model'])) {
$model = $result['node_details']['model'];
}
if (isset($result['tunnels']['tunnel_installed'])) {
$tunnel_installed = $result['tunnels']['tunnel_installed'];
}
if (isset($result['tunnels']['active_tunnel_count'])) {
$active_tunnel_count = $result['tunnels']['active_tunnel_count'];
}
if (isset($result['node_details']['firmware_mfg'])) {
$firmware_mfg = $result['node_details']['firmware_mfg'];
}
}
//had to screen scrape the status page for this info before
//which required an additional call to the node
//now it is here! :)
$uptime = "NotAvailable";
$loadavg = "NotAvailable";
if (version_compare($api_version, "1.2", ">=")) {
if (isset($result['sysinfo']['uptime'])) {
$uptime = $result['sysinfo']['uptime'];
}
if (isset($result['sysinfo']['loads'])) {
$loadavg = serialize($result['sysinfo']['loads']); // <-- this is an array that has been serialized!!
}
}
//local service listing are now in the json file!! yay!
//this required an additional call to port 9090 on the node before
$services = "NotAvailable";
if (version_compare($api_version, "1.3", ">=")) {
if (isset($result['services_local'])) {
$services = serialize($result['services_local']); // <-- this is an array that has been serialized!
}
}
//this only seems to affect some nodes.
//if grid_square is blank, make it "none"
//this was sometimes screwing up the SQL writing function
//but not always of course.
if ($grid_square == "") {
$grid_square = "none";
}
//else {
// $grid_square = $result['grid_square'];
//}
//W6BI requested this info to be added, so here it is now. :)
//current ip/mac address info
if ($result['interfaces']) {
foreach($result['interfaces'] as $interface => $infInfo) {
$eth = "eth0";
$wlan = "wlan0";
if ($model == "Ubiquiti Nanostation M XW" || $model == "AirRouter " || $model == "NanoStation M5 XW ") {
//"AirRouter " model name bug caught and fixed by Mark, N2MH 13 March 2017.
$eth = "eth0.0";
}
if ($model == "MikroTik RouterBOARD 952Ui-5ac2nD ") {
$eth = "eth1.0";
}
//!!!THERE IS ONLY 1 Wireless interface available on this device so far!!!
//this will be changed in the near future.
if ($model == "MikroTik RouterBOARD 952Ui-5ac2nD ") {
$wlan = "wlan1";
}
if(is_array($result)) {
//
// This should catch some of those pesky ones
// finally!
//parse json data (this is where the real heart is)
//
if (is_numeric($interface)) {
if ($infInfo['name'] == $eth) {
if (isset($infInfo['ip'])) {
if ($infInfo['ip'] == 'none') {
$lan_ip = "NotAvailable";
//variables and defaults
$meshRF = "on";
$ethInf = "eth0";
$wlanInf = "wlan0";
$node = "";
$wlan_ip = "";
$uptime = "Not Available";
$loadavg = "Not Available";
$model = "Not Available";