diff options
Diffstat (limited to 'modules-available/remoteaccess/inc/remoteaccess.inc.php')
-rw-r--r-- | modules-available/remoteaccess/inc/remoteaccess.inc.php | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/modules-available/remoteaccess/inc/remoteaccess.inc.php b/modules-available/remoteaccess/inc/remoteaccess.inc.php new file mode 100644 index 00000000..95ca3821 --- /dev/null +++ b/modules-available/remoteaccess/inc/remoteaccess.inc.php @@ -0,0 +1,117 @@ +<?php + +class RemoteAccess +{ + + const PROP_ALLOWED_VNC_NET = 'remoteaccess.allowedvncaccess'; + + const PROP_TRY_VIRT_HANDOVER = 'remoteaccess.virthandover'; + + const PROP_VNC_PORT = 'remoteaccess.vncport'; + + const PROP_PLUGIN_VERSION = 'remoteaccess.plugin-version'; + + /** + * Get a list of locationIds where remote access is enabled. If $filterOverridden is true, + * the list will not contain any locations where remote access is disabled via location override. + * @param int $group Group to get locations for, or '0' for all locations + * @param bool $filterOverridden iff true, remove any locations where remote access is currently disabled + */ + public static function getEnabledLocations(int $group = 0, bool $filterOverridden = true): array + { + if ($group === 0) { + $list = Database::queryColumnArray("SELECT DISTINCT rxl.locationid FROM remoteaccess_x_location rxl + INNER JOIN remoteaccess_group g ON (g.groupid = rxl.groupid AND g.active = 1)"); + } else { + $list = Database::queryColumnArray("SELECT DISTINCT locationid FROM remoteaccess_x_location + WHERE groupid = :gid", ['gid' => $group]); + } + if (!$filterOverridden || !Module::isAvailable('rebootcontrol')) + return $list; + return array_filter($list, function (int $lid) { + $mode = Scheduler::getLocationOptions($lid)['ra-mode']; + return ($mode !== Scheduler::RA_NEVER + && ($mode !== Scheduler::RA_SELECTIVE || !OpeningTimes::isRoomOpen($lid, 5, 5))); + }); + } + + public static function ensureMachinesRunning() + { + if (!Module::isAvailable('rebootcontrol')) { + error_log("Not waking remote access machines: rebootcontrol missing"); + return; + } + + $res = Database::simpleQuery("SELECT rg.groupid, rg.groupname, rg.wolcount, + GROUP_CONCAT(rxl.locationid) AS locs + FROM remoteaccess_group rg + INNER JOIN remoteaccess_x_location rxl USING (groupid) + WHERE rg.active = 1 + GROUP BY groupid"); + + // Consider machines we tried to wake in the past 90 seconds as online + $wolDeadline = time() - 90; + foreach ($res as $row) { + $wantNum = $row['wolcount']; + // This can't really be anything but a CSV list, but better be safe + $locs = preg_replace('/[^0-9,]/', '', $row['locs']); + if (!empty($locs)) { + // Filter out locations for which remote-access is disabled + $locArray = explode(',', $locs); + $locArray = array_filter($locArray, function (int $lid) { + $mode = Scheduler::getLocationOptions($lid)['ra-mode']; + return ($mode !== Scheduler::RA_NEVER + && ($mode !== Scheduler::RA_SELECTIVE || !OpeningTimes::isRoomOpen($lid, 5, 5))); + }); + $locs = implode(',', $locArray); + } + if ($wantNum > 0 && !empty($locs)) { + $active = Database::queryFirst("SELECT Count(*) AS cnt FROM machine m + INNER JOIN remoteaccess_machine rm USING (machineuuid) + WHERE m.locationid IN ($locs) AND (m.state = 'IDLE' OR rm.woltime > $wolDeadline)"); + $active = ($active['cnt'] ?? 0); + $wantNum -= $active; + } + if ($wantNum > 0) { + $numFailed = self::tryWakeMachines($locs, $wantNum); + } else { + $numFailed = 0; + } + Database::exec("UPDATE remoteaccess_group SET unwoken = :num WHERE groupid = :groupid", + ['num' => $numFailed, 'groupid' => $row['groupid']]); + } + } + + private static function tryWakeMachines(string $locs, int $num): int + { + if (empty($locs)) + return $num; + $res = Database::simpleQuery("SELECT m.machineuuid, m.macaddr, m.clientip, m.locationid FROM machine m + LEFT JOIN remoteaccess_machine rm USING (machineuuid) + WHERE m.locationid IN ($locs) AND m.state IN ('OFFLINE', 'STANDBY') + ORDER BY rm.woltime ASC"); + $NOW = time(); + while ($num > 0) { + $list = []; + for ($i = 0; $i < $num && ($row = $res->fetch()); ++$i) { + $list[] = $row; + Database::exec("INSERT INTO remoteaccess_machine (machineuuid, password, woltime) + VALUES (:uuid, NULL, :now) + ON DUPLICATE KEY UPDATE woltime = VALUES(woltime)", + ['uuid' => $row['machineuuid'], 'now' => $NOW]); + } + if (empty($list)) + break; // No more clients in this location + RebootControl::wakeMachines($list, $fails); + $num -= (count($list) - count($fails)); + if (!empty($fails)) { + $failIds = ArrayUtil::flattenByKey($fails, 'machineuuid'); + // Reduce time so they won't be marked as wol_in_progress + Database::exec('UPDATE remoteaccess_machine SET woltime = :faketime WHERE machineuuid IN (:fails)', + ['faketime' => $NOW - 95, 'fails' => $failIds]); + } + } + return $num; + } + +} |