Skip to content
This repository was archived by the owner on Aug 9, 2021. It is now read-only.

Commit 3667313

Browse files
committed
refactor(mqtt): refactor daemon and mqtt test button"
1 parent 75f4e08 commit 3667313

File tree

6 files changed

+390
-358
lines changed

6 files changed

+390
-358
lines changed

ajax/mqtt_test.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,8 @@
3030
*/
3131

3232
// Needs to be removed if this entry point needs to autoload a class from the plugin.
33-
//$AJAX_INCLUDE = 1;
3433
include ('../../../inc/includes.php');
3534

36-
//define("PLUGIN_FLYVEMDM_ROOT", $CFG_GLPI['root_doc'] . "/plugins/flyvemdm");
37-
3835
header("Content-Type: text/html; charset=UTF-8");
3936
Html::header_nocache();
4037
Session::checkLoginUser();

config.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ window.onload = function() {
1515
} else {
1616
$('#pluginFlyvemdm-test-feedback').empty().append(failIcon);
1717
}
18-
19-
});
20-
return false;
18+
});
19+
return false;
2120
});
2221
};

scripts/Daemon.php

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
<?php
2+
/**
3+
* LICENSE
4+
*
5+
* Copyright © 2016-2017 Teclib'
6+
* Copyright © 2010-2016 by the FusionInventory Development Team.
7+
*
8+
* This file is part of Flyve MDM Plugin for GLPI.
9+
*
10+
* Flyve MDM Plugin for GLPI is a subproject of Flyve MDM. Flyve MDM is a mobile
11+
* device management software.
12+
*
13+
* Flyve MDM Plugin for GLPI is free software: you can redistribute it and/or
14+
* modify it under the terms of the GNU Affero General Public License as published
15+
* by the Free Software Foundation, either version 3 of the License, or
16+
* (at your option) any later version.
17+
* Flyve MDM Plugin for GLPI is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with Flyve MDM Plugin for GLPI. If not, see http://www.gnu.org/licenses/.
23+
* ------------------------------------------------------------------------------
24+
* @author Thierry Bugier Pineau
25+
* @author Volker Theile <[email protected]>
26+
* @copyright Copyright © 2017 Teclib
27+
* @license AGPLv3+ http://www.gnu.org/licenses/agpl.txt
28+
* @link https://github.com/flyve-mdm/flyve-mdm-glpi
29+
* @link https://flyve-mdm.com/
30+
* ------------------------------------------------------------------------------
31+
*/
32+
33+
/*
34+
* based on RPC daemon of Openmediavault
35+
* https://raw.githubusercontent.com/openmediavault/openmediavault/master/deb/openmediavault/usr/sbin/omv-engined
36+
*/
37+
38+
abstract class Daemon implements DaemonInterface {
39+
private static $sigTerm = false;
40+
private static $sigChld = false;
41+
private $socket = null;
42+
private $maxConnections = 10;
43+
private $timeout = 1;
44+
private static $debug = false;
45+
private static $daemon = true;
46+
private $xdebug = false;
47+
private $pidFile = null;
48+
private static $children = [];
49+
50+
private $stdIn = null;
51+
private $stdOut = null;
52+
private $stdErr = null;
53+
54+
function main($argc, $argv) {
55+
set_error_handler(__CLASS__ . '::errorHandler');
56+
register_shutdown_function(__CLASS__ . '::shutdownHandler');
57+
58+
$this->cmdName = basename($argv[0]);
59+
$this->pidFile = "/var/run/$this->cmdName.pid";
60+
61+
// Check the command line arguments. Exit and display usage if
62+
// nessecary.
63+
$cmdArgs = [
64+
'd::' => 'debug::',
65+
'f::' => 'foreground::',
66+
'h::' => 'help::',
67+
'x::' => 'xdebug::'
68+
];
69+
$options = getopt(implode('', array_keys($cmdArgs)), $cmdArgs);
70+
foreach ($options as $optionk => $optionv) {
71+
switch ($optionk) {
72+
case 'd':
73+
case 'debug':
74+
$argc -= 1;
75+
self::$debug = true;
76+
break;
77+
case 'f':
78+
case 'foreground':
79+
$argc -= 1;
80+
self::$daemon = false;
81+
break;
82+
case 'h':
83+
case 'help':
84+
$this->usage();
85+
exit(0);
86+
break;
87+
case 'x':
88+
case 'xdebug':
89+
$argc -= 1;
90+
$this->xdebug = true;
91+
break;
92+
}
93+
}
94+
if ($argc > 1) {
95+
print gettext('ERROR: Invalid number of arguments\n');
96+
$this->usage();
97+
exit(1);
98+
}
99+
100+
ini_set('max_execution_time', '0');
101+
ini_set('max_input_time', '0');
102+
set_time_limit(0);
103+
104+
// Open syslog, include the process ID and also send the log to
105+
// standard error.
106+
openlog($this->cmdName, LOG_PID | LOG_PERROR, LOG_USER);
107+
108+
// Change process name.
109+
cli_set_process_title($this->cmdName);
110+
111+
$this->daemonize();
112+
113+
if (!pcntl_signal(SIGINT, __CLASS__ . '::signalHandler')
114+
|| !pcntl_signal(SIGTERM, __CLASS__ . '::signalHandler')
115+
|| !pcntl_signal(SIGCHLD, __CLASS__ . '::signalHandler')) {
116+
$this->debug('Failed to setup signal handlers' . PHP_EOL);
117+
}
118+
//$this->debug(pcntl_signal_get_handler(SIGINT) . PHP_EOL);
119+
//$this->debug(pcntl_signal_get_handler(SIGTERM) . PHP_EOL);
120+
//$this->debug(pcntl_signal_get_handler(SIGCHLD) . PHP_EOL);
121+
122+
$this->loop();
123+
}
124+
125+
/**
126+
* Display command usage.
127+
*/
128+
private function usage() {
129+
$text = <<<EOF
130+
The MQTT subscriber daemon. MQTT messages will be received via a socket.
131+
Usage:
132+
%s [options]
133+
134+
OPTIONS:
135+
-d --debug Enable debug mode
136+
-f --foreground Run in foreground
137+
-h --help Print a help text
138+
-x --xdebug Enable XDebug compatibility mode
139+
140+
EOF;
141+
printf($text, $this->cmdName);
142+
}
143+
144+
/**
145+
* Signal handler function.
146+
*
147+
* @param signal The signal.
148+
*/
149+
public static function signalHandler($signal) {
150+
switch ($signal) {
151+
case SIGINT:
152+
self::debug("SIGINT received ...\n");
153+
self::$sigTerm = true;
154+
break;
155+
case SIGTERM:
156+
self::debug("SIGTERM received ...\n");
157+
self::$sigTerm = true;
158+
break;
159+
case SIGCHLD:
160+
self::debug("SIGCHLD received ...\n");
161+
self::$sigChld = true;
162+
break;
163+
default:
164+
// Nothing to do here.
165+
break;
166+
}
167+
}
168+
169+
/**
170+
* Process SIGCHLD signals.
171+
*/
172+
private static function handleSigChld() {
173+
$status = null;
174+
while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) > 0) {
175+
foreach (self::$children as $childk => $childv) {
176+
if ($childv !== $pid) {
177+
continue;
178+
}
179+
unset(self::$children[$childk]);
180+
if (pcntl_wifexited($status)) {
181+
self::debug("Child (pid=%d) terminated with exit code %d\n",
182+
$pid, pcntl_wexitstatus($status));
183+
} else {
184+
self::debug("Child (pid=%d) terminated with signal %d\n",
185+
$pid, pcntl_wtermsig($status));
186+
}
187+
break;
188+
}
189+
}
190+
self::$sigChld = false;
191+
}
192+
193+
/**
194+
* Kill all child processes.
195+
*/
196+
private static function killChld() {
197+
foreach (self::$children as $childv) {
198+
if (posix_kill($childv, SIGTERM)) {
199+
self::debug("Send SIGTERM to child (pid=%d)\n", $childv);
200+
}
201+
}
202+
while (!empty(self::$children)) {
203+
debug("Waiting for children to terminate ...\n");
204+
self::handleSigChld();
205+
usleep(1000);
206+
}
207+
}
208+
209+
/**
210+
* Daemonize the application.
211+
* @see http://www.freedesktop.org/software/systemd/man/daemon.html
212+
* @see http://stackoverflow.com/a/17955149
213+
* @see https://stackoverflow.com/questions/881388/what-is-the-reason-for-performing-a-double-fork-when-creating-a-daemon
214+
*/
215+
private function daemonize() {
216+
if (!self::$daemon) {
217+
return;
218+
}
219+
220+
// Check if PID file already exists and whether a daemon is already
221+
// running.
222+
if (file_exists($this->pidFile)) {
223+
$pid = file_get_contents($this->pidFile);
224+
if(posix_kill($pid, 0) === true) {
225+
self::error("Daemon already running (pid=%d)\n", $pid);
226+
exit(1);
227+
}
228+
unlink($this->pidFile);
229+
}
230+
231+
$pid = pcntl_fork();
232+
if ($pid == -1) {
233+
self::error("Failed to fork process\n");
234+
exit(1);
235+
} else if($pid) { // Parent process
236+
exit(0);
237+
}
238+
239+
// Make the current process a session leader.
240+
if (posix_setsid() < 0) {
241+
self::error("Could not detach from terminal\n");
242+
exit(1);
243+
}
244+
245+
// Ignore signals.
246+
pcntl_signal(SIGHUP, SIG_IGN);
247+
248+
// If starting a process on the command line, the shell will become the
249+
// session leader of that command. To create a new process group with the
250+
// daemon as session leader it is necessary to fork a new process again.
251+
$pid = pcntl_fork();
252+
if ($pid == -1) {
253+
self::error("Failed to fork process\n");
254+
exit(1);
255+
} else if($pid) { // Parent process
256+
self::debug("Daemon process started (pid=%d)\n", $pid);
257+
// Exit parent process.
258+
exit(0);
259+
}
260+
261+
// Change the current working directory.
262+
if (chdir(__DIR__) === false) {
263+
self::error("Failed to change current directory\n");
264+
exit(1);
265+
}
266+
267+
// Create PID file.
268+
file_put_contents($this->pidFile, posix_getpid());
269+
270+
if (!$this->debug) {
271+
// Close all of the standard file descriptors.
272+
if (is_resource(STDIN)) fclose(STDIN);
273+
if (is_resource(STDOUT)) fclose(STDOUT);
274+
if (is_resource(STDERR)) fclose(STDERR);
275+
// Create new standard file descriptors.
276+
$this->stdIn = fopen("/dev/null", "r");
277+
$this->stdOut = fopen("/dev/null", "w");
278+
$this->stdErr = fopen("/dev/null", "w");
279+
}
280+
}
281+
282+
/**
283+
* Error function. Output message to system log and console in debug mode.
284+
* @param msg The error message.
285+
*/
286+
private static function error() {
287+
$args = func_get_args();
288+
$msg = array_shift($args);
289+
// Log the message in syslog.
290+
syslog(LOG_ALERT, vsprintf($msg, $args));
291+
// Print the message to STDOUT if debug mode is enabled.
292+
if (self::$debug) {
293+
// Append a new line if necessary.
294+
if ("\n" !== substr($msg, -1))
295+
$msg .= "\n";
296+
// Print the message to STDOUT.
297+
vprintf($msg, $args);
298+
}
299+
}
300+
301+
/**
302+
* Debug function. Output message to syslog or console in debug mode.
303+
* @param msg The debug message.
304+
*/
305+
private static function debug() {
306+
$args = func_get_args();
307+
$msg = array_shift($args);
308+
if (self::$debug) {
309+
if (!self::$daemon) {
310+
vprintf($msg, $args);
311+
} else {
312+
syslog(LOG_DEBUG, vsprintf($msg, $args));
313+
}
314+
}
315+
}
316+
317+
/**
318+
* The error handler.
319+
*/
320+
public static function errorHandler($errno, $errstr, $errfile, $errline) {
321+
switch ($errno) {
322+
case E_RECOVERABLE_ERROR:
323+
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
324+
break;
325+
default:
326+
// Nothing to do here.
327+
break;
328+
}
329+
// Don't execute the PHP internal error handler.
330+
return true;
331+
}
332+
333+
/**
334+
* The function for execution on shutdown.
335+
*/
336+
public static function shutdownHandler() {
337+
// Check if there was a fatal error.
338+
$error = error_get_last();
339+
if (!is_null($error) && (E_ERROR == $error['type'])) {
340+
// Log fatal errors to syslog.
341+
self::error("PHP Fatal error: %s in %s on line %d", $error['message'],
342+
$error['file'], $error['line']);
343+
}
344+
}
345+
346+
protected function getDebug() {
347+
return self::$debug;
348+
}
349+
}

scripts/DaemonInterface.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
interface DaemonInterface {
3+
public function loop();
4+
}

0 commit comments

Comments
 (0)