PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/code/classes/Daemon/PMaild/MTA.class.php

https://github.com/blekkzor/pinetd2
PHP | 126 lines | 96 code | 18 blank | 12 comment | 18 complexity | ff657efb683de22ae66f84fc8971bbb4 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. namespace Daemon\PMaild;
  3. use pinetd\Logger;
  4. use pinetd\SQL;
  5. use pinetd\IPC;
  6. use pinetd\Timer;
  7. class MTA extends \pinetd\Process {
  8. protected $agents = array();
  9. protected $checkPeriod = 0;
  10. protected $sql;
  11. protected $error = array();
  12. public function __construct($id, $daemon, $IPC, $node) {
  13. parent::__construct($id, $daemon, $IPC, $node);
  14. // check tables struct
  15. $this->sql = SQL::Factory($this->localConfig['Storage']);
  16. $class = relativeclass($this, 'MTA\\Storage');
  17. $class::validateTables($this->sql);
  18. // check each domain's tables struct
  19. $DAO = $this->sql->DAO('domains', 'domainid');
  20. $data = $DAO->loadByField(null);
  21. foreach($data as $domain) {
  22. $class::validateTables($this->sql, $domain->domainid);
  23. }
  24. }
  25. protected function launchChildsIfNeeded() {
  26. // check if we have any chance to load any new agent anyway?
  27. if (count($this->agents) >= $this->localConfig['MTA']['MaxProcesses']) return;
  28. // shall we check again if we need new childs ?
  29. if ($this->checkPeriod > time()) return;
  30. $this->checkPeriod = time()+5;
  31. // get current queue count
  32. $req = 'SELECT COUNT(1) FROM `mailqueue` WHERE (`next_attempt` < NOW() OR `next_attempt` IS NULL) AND `pid` IS NULL';
  33. $res = $this->sql->query($req);
  34. if (!$res) return; // ?!
  35. $res = $res->fetch_row();
  36. $count = $res[0];
  37. if ($count == 0) return; // no pending mail
  38. $to_start = floor($count/$this->localConfig['MTA']['StartThreshold']);
  39. // apply limits
  40. if ($to_start == 0) $to_start = 1;
  41. if ($to_start > $this->localConfig['MTA']['MaxProcesses']) $to_start = $this->localConfig['MTA']['MaxProcesses'];
  42. if (count($this->agents) >= $to_start) return; // already have enough
  43. Logger::log(Logger::LOG_DEBUG, 'Requiring '.$to_start.' daemons for handling delivery of '.$count.' mails');
  44. for($i=count($this->agents);$i<$to_start;$i++) $this->launchAgent();
  45. }
  46. protected function launchAgent() {
  47. $pair = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
  48. $pid = pcntl_fork();
  49. if ($pid > 0) {
  50. // parent's speaking
  51. SQL::parentForked(); // close all sql links to avoid bugs
  52. fclose($pair[1]);
  53. $this->agents[$pid] = array(
  54. 'pid' => $pid,
  55. 'launch' => time(),
  56. 'IPC' => new IPC($pair[0], false, $this, $this->IPC),
  57. );
  58. $this->IPC->registerSocketWait($pair[0], array($this->agents[$pid]['IPC'], 'run'), $foobar = array(&$this->agents[$pid]));
  59. return true;
  60. }
  61. if ($pid == 0) {
  62. SQL::parentForked(); // close all sql links to avoid bugs
  63. Timer::reset();
  64. fclose($pair[0]);
  65. $IPC = new IPC($pair[1], true, $foo = null, $this->IPC);
  66. $IPC->ping();
  67. Logger::setIPC($IPC);
  68. Logger::log(Logger::LOG_DEBUG, 'MTA started with pid '.getmypid());
  69. $class = relativeclass($this, 'MTA_Child');
  70. $child = new $class($IPC);
  71. $child->mainLoop($IPC);
  72. exit;
  73. }
  74. }
  75. public function IPCDied($fd) {
  76. // $info = $this->IPC->getSocketInfo($fd);
  77. $this->IPC->removeSocket($fd);
  78. // $info = &$this->fclients[$info['pid']];
  79. // Logger::log(Logger::LOG_WARN, 'IPC for '.$info['pid'].' died');
  80. }
  81. public function shutdown() {
  82. // send stop signal to clients
  83. Logger::log(Logger::LOG_INFO, 'MTA stopping...');
  84. foreach($this->agents as $pid => $data) {
  85. $data['IPC']->stop();
  86. }
  87. return true;
  88. }
  89. public function mainLoop() {
  90. parent::initMainLoop();
  91. while(1) {
  92. $this->launchChildsIfNeeded();
  93. $this->IPC->selectSockets(200000);
  94. }
  95. }
  96. public function childSignaled($res, $status, $signal = NULL) {
  97. if (count($this->agents) == 0) return; // nothing to do
  98. // search what ended
  99. $ended = $this->agents[$res];
  100. if (is_null($ended)) return; // we do not know what ended
  101. if (is_null($signal)) {
  102. Logger::log(Logger::LOG_DEBUG, 'MTAgent with pid #'.$res.' exited');
  103. } else {
  104. Logger::log(Logger::LOG_INFO, 'MTAgent with pid #'.$res.' died due to signal '.$signal);
  105. }
  106. unset($this->agents[$res]);
  107. }
  108. }