1
0

Fluxd.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. <?php
  2. /* $Id: Fluxd.php 3057 2007-05-27 13:06:39Z b4rt $ */
  3. /*******************************************************************************
  4. LICENSE
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License (GPL)
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. To read the license please visit http://www.gnu.org/copyleft/gpl.html
  14. *******************************************************************************/
  15. // states
  16. define('FLUXD_STATE_NULL', 0); // null
  17. define('FLUXD_STATE_RUNNING', 1); // running
  18. define('FLUXD_STATE_ERROR', -1); // error
  19. // delims of modList
  20. define('FLUXD_DELIM_MOD', ';');
  21. define('FLUXD_DELIM_STATE', ':');
  22. /**
  23. * class Fluxd for integration of fluxd
  24. */
  25. class Fluxd
  26. {
  27. // public fields
  28. // state
  29. var $state = FLUXD_STATE_NULL;
  30. // messages-array
  31. var $messages = array();
  32. // private fields
  33. // pid
  34. var $_pid = "";
  35. // some path-vars for Fluxd
  36. var $_pathDataDir = "";
  37. var $_pathPidFile = "";
  38. var $_pathSocket = "";
  39. var $_pathLogFile = "";
  40. var $_pathLogFileError = "";
  41. // mod-list, only loaded first time it is needed
  42. var $_modList = null;
  43. // socket-timeout
  44. var $_socketTimeout = 5;
  45. // =========================================================================
  46. // public static methods
  47. // =========================================================================
  48. /**
  49. * accessor for singleton
  50. *
  51. * @return Fluxd
  52. */
  53. function getInstance() {
  54. global $instanceFluxd;
  55. // initialize if needed
  56. if (!isset($instanceFluxd))
  57. Fluxd::initialize();
  58. return $instanceFluxd;
  59. }
  60. /**
  61. * initialize Fluxd.
  62. */
  63. function initialize() {
  64. global $instanceFluxd;
  65. // create instance
  66. if (!isset($instanceFluxd))
  67. $instanceFluxd = new Fluxd();
  68. }
  69. /**
  70. * accessor for state
  71. *
  72. * @return int
  73. */
  74. function getState() {
  75. global $instanceFluxd;
  76. return $instanceFluxd->state;
  77. }
  78. /**
  79. * getMessages
  80. *
  81. * @return array
  82. */
  83. function getMessages() {
  84. global $instanceFluxd;
  85. return $instanceFluxd->messages;
  86. }
  87. /**
  88. * isRunning
  89. *
  90. * @return boolean
  91. */
  92. function isRunning() {
  93. global $instanceFluxd;
  94. return ($instanceFluxd->state == FLUXD_STATE_RUNNING);
  95. }
  96. /**
  97. * start
  98. *
  99. * @return boolean
  100. */
  101. function start() {
  102. global $instanceFluxd;
  103. return $instanceFluxd->instance_start();
  104. }
  105. /**
  106. * stop
  107. */
  108. function stop() {
  109. global $instanceFluxd;
  110. return $instanceFluxd->instance_stop();
  111. }
  112. /**
  113. * getPid
  114. *
  115. * @return int with pid
  116. */
  117. function getPid() {
  118. global $instanceFluxd;
  119. return $instanceFluxd->instance_getPid();
  120. }
  121. /**
  122. * status
  123. *
  124. * @return string
  125. */
  126. function status() {
  127. global $instanceFluxd;
  128. return $instanceFluxd->instance_status();
  129. }
  130. /**
  131. * modState
  132. *
  133. * @param name of service-module
  134. * @return int with mod-state
  135. */
  136. function modState($mod) {
  137. global $instanceFluxd;
  138. return $instanceFluxd->instance_modState($mod);
  139. }
  140. /**
  141. * modList
  142. *
  143. * @return array with mod-list
  144. */
  145. function modList() {
  146. global $instanceFluxd;
  147. return $instanceFluxd->instance_modList();
  148. }
  149. /**
  150. * modStatePoll
  151. *
  152. * @param name of service-module
  153. * @return int with mod-state
  154. */
  155. function modStatePoll($mod) {
  156. global $instanceFluxd;
  157. return $instanceFluxd->instance_modStatePoll($mod);
  158. }
  159. /**
  160. * modListPoll
  161. *
  162. * @return array with mod-list
  163. */
  164. function modListPoll() {
  165. global $instanceFluxd;
  166. return $instanceFluxd->instance_modListPoll();
  167. }
  168. /**
  169. * isReadyToStart
  170. *
  171. * @return boolean
  172. */
  173. function isReadyToStart() {
  174. global $instanceFluxd;
  175. return $instanceFluxd->instance_isReadyToStart();
  176. }
  177. /**
  178. * setConfig
  179. *
  180. * @param $key, $value
  181. * @return Null
  182. */
  183. function setConfig($key, $value) {
  184. global $instanceFluxd;
  185. $instanceFluxd->instance_setConfig($key, $value);
  186. }
  187. /**
  188. * reloadDBCache
  189. */
  190. function reloadDBCache() {
  191. global $instanceFluxd;
  192. $instanceFluxd->instance_reloadDBCache();
  193. }
  194. /**
  195. * reloadModules
  196. */
  197. function reloadModules() {
  198. global $instanceFluxd;
  199. $instanceFluxd->instance_reloadModules();
  200. }
  201. /**
  202. * writes a message to the log
  203. *
  204. * @param $message
  205. * @param $withTS
  206. * @return boolean
  207. */
  208. function logMessage($message, $withTS = true) {
  209. global $instanceFluxd;
  210. return $instanceFluxd->instance_logMessage($message, $withTS);
  211. }
  212. /**
  213. * writes a message to the error-log
  214. *
  215. * @param $message
  216. * @param $withTS
  217. * @return boolean
  218. */
  219. function logError($message, $withTS = true) {
  220. global $instanceFluxd;
  221. return $instanceFluxd->instance_logError($message, $withTS);
  222. }
  223. /**
  224. * send command
  225. *
  226. * @param $command
  227. * @param $read does this command return something ?
  228. * @return string with retval or null if error
  229. */
  230. function sendCommand($command, $read = 0) {
  231. global $instanceFluxd;
  232. return $instanceFluxd->instance_sendCommand($command, $read);
  233. }
  234. /**
  235. * send service command
  236. *
  237. * @param $command
  238. * @param $read does this command return something ?
  239. * @return string with retval or null if error
  240. */
  241. function sendServiceCommand($mod, $command, $read = 0) {
  242. global $instanceFluxd;
  243. return $instanceFluxd->instance_sendCommand('!'.$mod.':'.$command, $read);
  244. }
  245. // =========================================================================
  246. // ctor
  247. // =========================================================================
  248. /**
  249. * ctor
  250. */
  251. function Fluxd() {
  252. global $cfg;
  253. // paths
  254. $this->_pathDataDir = $cfg["path"] . '.fluxd/';
  255. $this->_pathPidFile = $this->_pathDataDir . 'fluxd.pid';
  256. $this->_pathSocket = $this->_pathDataDir . 'fluxd.sock';
  257. $this->_pathLogFile = $this->_pathDataDir . 'fluxd.log';
  258. $this->_pathLogFileError = $this->_pathDataDir . 'fluxd-error.log';
  259. // check if fluxd running
  260. if ($this->_isRunning())
  261. $this->state = FLUXD_STATE_RUNNING;
  262. }
  263. // =========================================================================
  264. // public methods
  265. // =========================================================================
  266. /**
  267. * instance_start
  268. *
  269. * @return boolean
  270. */
  271. function instance_start() {
  272. global $cfg;
  273. if ($this->state == FLUXD_STATE_RUNNING) {
  274. AuditAction($cfg["constants"]["error"], "fluxd already started");
  275. return false;
  276. } else {
  277. // check the needed bins
  278. // perl
  279. if (@file_exists($cfg['perlCmd']) !== true) {
  280. $msg = "cannot start fluxd, specified Perl-binary does not exist: ".$cfg['perlCmd'];
  281. AuditAction($cfg["constants"]["error"], $msg);
  282. array_push($this->messages , $msg);
  283. // Set the state
  284. $this->state = FLUXD_STATE_ERROR;
  285. // return
  286. return false;
  287. }
  288. // php-cli
  289. if (@file_exists($cfg['bin_php']) !== true) {
  290. $msg = "cannot start fluxd, specified php-cli-binary does not exist: ".$cfg['bin_php'];
  291. AuditAction($cfg["constants"]["error"], $msg);
  292. array_push($this->messages , $msg);
  293. // Set the state
  294. $this->state = FLUXD_STATE_ERROR;
  295. // return
  296. return false;
  297. }
  298. // check for sockets
  299. $loadedExtensions = get_loaded_extensions();
  300. if (!in_array("sockets", $loadedExtensions)) {
  301. $msg = "refusing to start fluxd, PHP does not have support for sockets";
  302. AuditAction($cfg["constants"]["error"], $msg);
  303. array_push($this->messages , $msg);
  304. // Set the state
  305. $this->state = FLUXD_STATE_ERROR;
  306. // return
  307. return false;
  308. }
  309. // start it
  310. $startCommand = "cd ".tfb_shellencode($cfg["docroot"])."; HOME=".tfb_shellencode($cfg["path"]).";";
  311. $startCommand .= " export HOME;";
  312. $startCommand .= " nohup " . $cfg["perlCmd"];
  313. $startCommand .= " -I ".tfb_shellencode($cfg["docroot"]."bin/fluxd");
  314. $startCommand .= " -I ".tfb_shellencode($cfg["docroot"]."bin/lib");
  315. $startCommand .= " ".tfb_shellencode($cfg["docroot"]."bin/fluxd/fluxd.pl");
  316. $startCommand .= " start";
  317. $startCommand .= " ".tfb_shellencode($cfg["docroot"]);
  318. $startCommand .= " ".tfb_shellencode($cfg["path"]);
  319. $startCommand .= " ".tfb_shellencode($cfg["bin_php"]);
  320. $startCommand .= " ".tfb_shellencode($cfg["fluxd_dbmode"]);
  321. $startCommand .= " 1>> ".tfb_shellencode($this->_pathLogFile);
  322. $startCommand .= " 2>> ".tfb_shellencode($this->_pathLogFileError);
  323. $startCommand .= " &";
  324. $this->instance_logMessage("executing command : \n".$startCommand."\n", true);
  325. // exec
  326. $result = exec($startCommand);
  327. // check if fluxd could be started
  328. $loop = true;
  329. $maxLoops = 125;
  330. $loopCtr = 0;
  331. $started = false;
  332. while ($loop) {
  333. @clearstatcache();
  334. if ($this->_isRunning()) {
  335. $started = true;
  336. $loop = false;
  337. } else {
  338. $loopCtr++;
  339. if ($loopCtr > $maxLoops)
  340. $loop = false;
  341. else
  342. usleep(200000); // wait for 0.2 seconds
  343. }
  344. }
  345. // check if started
  346. if ($started) {
  347. AuditAction($cfg["constants"]["fluxd"], "fluxd started");
  348. // Set the state
  349. $this->state = FLUXD_STATE_RUNNING;
  350. // return
  351. return true;
  352. } else {
  353. AuditAction($cfg["constants"]["error"], "errors starting fluxd");
  354. // add startcommand to messages for debug
  355. // TODO : set better message
  356. array_push($this->messages , $startCommand);
  357. // Set the state
  358. $this->state = FLUXD_STATE_ERROR;
  359. // return
  360. return false;
  361. }
  362. }
  363. }
  364. /**
  365. * instance_stop
  366. */
  367. function instance_stop() {
  368. global $cfg;
  369. if ($this->state == FLUXD_STATE_RUNNING) {
  370. AuditAction($cfg["constants"]["fluxd"], "Stopping fluxd");
  371. $this->instance_sendCommand('die', 0);
  372. // check if fluxd still running
  373. $maxLoops = 125;
  374. $loopCtr = 0;
  375. for (;;) {
  376. @clearstatcache();
  377. if ($this->_isRunning()) {
  378. $loopCtr++;
  379. if ($loopCtr > $maxLoops)
  380. return 0;
  381. else
  382. usleep(200000); // wait for 0.2 seconds
  383. } else {
  384. // Set the state
  385. $this->state = FLUXD_STATE_NULL;
  386. // return
  387. return 1;
  388. }
  389. }
  390. return 0;
  391. } else {
  392. $msg = "errors stopping fluxd as was not running.";
  393. AuditAction($cfg["constants"]["error"], $msg);
  394. array_push($this->messages , $msg);
  395. // Set the state
  396. $this->state = FLUXD_STATE_ERROR;
  397. return 0;
  398. }
  399. }
  400. /**
  401. * instance_getPid
  402. *
  403. * @return string with pid
  404. */
  405. function instance_getPid() {
  406. if ($this->_pid != "") {
  407. return $this->_pid;
  408. } else {
  409. $this->_pid = @rtrim(file_get_contents($this->_pathPidFile));
  410. return $this->_pid;
  411. }
  412. }
  413. /**
  414. * instance_status
  415. *
  416. * @return string
  417. */
  418. function instance_status() {
  419. return ($this->state == FLUXD_STATE_RUNNING)
  420. ? $this->instance_sendCommand('status', 1)
  421. : "";
  422. }
  423. /**
  424. * instance_modState
  425. *
  426. * @param name of service-module
  427. * @return string with mod-state
  428. */
  429. function instance_modState($mod) {
  430. if (is_null($this->_modList))
  431. $this->_modList = $this->instance_modListPoll();
  432. return $this->_modList[$mod];
  433. }
  434. /**
  435. * instance_modList
  436. *
  437. * @return array with mod-list
  438. */
  439. function instance_modList() {
  440. if (is_null($this->_modList))
  441. $this->_modList = $this->instance_modListPoll();
  442. return $this->_modList;
  443. }
  444. /**
  445. * instance_modStatePoll
  446. *
  447. * @param name of service-module
  448. * @return string with mod-state
  449. */
  450. function instance_modStatePoll($mod) {
  451. return ($this->state == FLUXD_STATE_RUNNING)
  452. ? $this->instance_sendCommand('modstate '.$mod, 1)
  453. : 0;
  454. }
  455. /**
  456. * instance_modListPoll
  457. *
  458. * @return array with mod-list
  459. */
  460. function instance_modListPoll() {
  461. global $cfg;
  462. $retVal = array();
  463. // get modlist
  464. if ($this->state == FLUXD_STATE_RUNNING) {
  465. $mods = trim($this->instance_sendCommand('modlist', 1));
  466. if (strlen($mods) > 0) {
  467. $modsAry = explode(FLUXD_DELIM_MOD, $mods);
  468. foreach ($modsAry as $mod)
  469. $retVal[substr($mod, 0, -2)] = substr($mod, -1);
  470. }
  471. }
  472. // make sure retVal contains cfg modules
  473. if ((empty($retVal)) && (!empty($cfg['fluxdServiceModList']))) {
  474. foreach ($cfg['fluxdServiceModList'] as $mod)
  475. $retVal[$mod] = 0;
  476. }
  477. // return
  478. return $retVal;
  479. }
  480. /**
  481. * instance_isReadyToStart
  482. *
  483. * @return boolean
  484. */
  485. function instance_isReadyToStart() {
  486. return ($this->state == FLUXD_STATE_RUNNING)
  487. ? false
  488. : (!($this->instance_sendCommand('worker', 0)));
  489. }
  490. /**
  491. * instance_setConfig
  492. *
  493. * @param $key, $value
  494. * @return Null
  495. */
  496. function instance_setConfig($key, $value) {
  497. if ($this->state == FLUXD_STATE_RUNNING)
  498. $this->instance_sendCommand('set '.$key.' '.$value, 0);
  499. }
  500. /**
  501. * instance_reloadDBCache
  502. */
  503. function instance_reloadDBCache() {
  504. if ($this->state == FLUXD_STATE_RUNNING)
  505. $this->instance_sendCommand('reloadDBCache', 0);
  506. }
  507. /**
  508. * instance_reloadModules
  509. */
  510. function instance_reloadModules() {
  511. if ($this->state == FLUXD_STATE_RUNNING)
  512. $this->instance_sendCommand('reloadModules', 0);
  513. }
  514. /**
  515. * writes a message to the log
  516. *
  517. * @param $message
  518. * @param $withTS
  519. * @return boolean
  520. */
  521. function instance_logMessage($message, $withTS = true) {
  522. return $this->_log($this->_pathLogFile, $message, $withTS);
  523. }
  524. /**
  525. * writes a message to the error-log
  526. *
  527. * @param $message
  528. * @param $withTS
  529. * @return boolean
  530. */
  531. function instance_logError($message, $withTS = true) {
  532. return $this->_log($this->_pathLogFileError, $message, $withTS);
  533. }
  534. /**
  535. * send command
  536. *
  537. * @param $command
  538. * @param $read does this command return something ?
  539. * @return string with retval or null if error
  540. */
  541. function instance_sendCommand($command, $read = 0) {
  542. if ($this->state == FLUXD_STATE_RUNNING) {
  543. // create socket
  544. $socket = @socket_create(AF_UNIX, SOCK_STREAM, 0);
  545. if ($socket === false) {
  546. array_push($this->messages , "socket_create() failed: reason: ".@socket_strerror(@socket_last_error()));
  547. $this->state = FLUXD_STATE_ERROR;
  548. return null;
  549. }
  550. //timeout after n seconds
  551. @socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $this->_socketTimeout, 'usec' => 0));
  552. // connect
  553. $result = @socket_connect($socket, $this->_pathSocket);
  554. if ($result === false) {
  555. array_push($this->messages , "socket_connect() failed: reason: ".@socket_strerror(@socket_last_error()));
  556. $this->state = FLUXD_STATE_ERROR;
  557. @socket_close($socket);
  558. return null;
  559. }
  560. // write command
  561. $result = @socket_write($socket, $command."\n");
  562. if ($result === false) {
  563. array_push($this->messages , "socket_write() failed: reason: ".@socket_strerror(@socket_last_error()));
  564. $this->state = FLUXD_STATE_ERROR;
  565. @socket_close($socket);
  566. return null;
  567. }
  568. // read retval
  569. $return = "";
  570. if ($read != 0) {
  571. do {
  572. // read data
  573. $data = @socket_read($socket, 4096, PHP_BINARY_READ);
  574. if ($data === false) {
  575. array_push($this->messages , "socket_read() failed: reason: ".@socket_strerror(@socket_last_error()));
  576. // Don't set global error in case of failure,
  577. // other calls might still succeed (e.g. in
  578. // case error was just a read timeout).
  579. //$this->state = FLUXD_STATE_ERROR;
  580. @socket_close($socket);
  581. return null;
  582. }
  583. $return .= $data;
  584. } while (isset($data) && ($data != ""));
  585. }
  586. // close socket
  587. @socket_close($socket);
  588. // return
  589. return $return;
  590. } else { // fluxd not running
  591. return null;
  592. }
  593. }
  594. // =========================================================================
  595. // private methods
  596. // =========================================================================
  597. /**
  598. * _isRunning
  599. *
  600. * @return boolean
  601. */
  602. function _isRunning() {
  603. return file_exists($this->_pathPidFile);
  604. }
  605. /**
  606. * log a message
  607. *
  608. * @param $logFile
  609. * @param $message
  610. * @param $withTS
  611. * @return boolean
  612. */
  613. function _log($logFile, $message, $withTS = false) {
  614. $content = "";
  615. if ($withTS)
  616. $content .= @date("[Y/m/d - H:i:s]");
  617. $content .= '[FRONTEND] ';
  618. $content .= $message;
  619. $fp = false;
  620. $fp = @fopen($logFile, "a+");
  621. if (!$fp)
  622. return false;
  623. $result = @fwrite($fp, $content);
  624. @fclose($fp);
  625. if ($result === false)
  626. return false;
  627. return true;
  628. }
  629. }
  630. ?>