PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/code/classes/Daemon/DNSd/Process.class.php

https://github.com/blekkzor/pinetd2
PHP | 174 lines | 130 code | 36 blank | 8 comment | 18 complexity | 815115a4466a5cd50c2651efa7371c7b MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. namespace Daemon\DNSd;
  3. use pinetd\Timer;
  4. use pinetd\Logger;
  5. class Process extends \pinetd\Process {
  6. private $master_link = NULL;
  7. private $status = 0;
  8. private $buf = '';
  9. private $db_engine;
  10. public function __construct($id, $daemon, $IPC, $node) {
  11. parent::__construct($id, $daemon, $IPC, $node);
  12. }
  13. public function pingMaster(&$extra = null) {
  14. if (!is_null($this->master_link)) $this->sendPkt('Ping');
  15. }
  16. public function checkMaster(&$extra = null) {
  17. if (!isset($this->localConfig['Master'])) return true;
  18. if (is_null($this->master_link)) {
  19. Logger::log(Logger::LOG_INFO, 'Connecting to DNSd master');
  20. $config = $this->localConfig['Master'];
  21. $this->master_link = @stream_socket_client('tcp://'.$config['Host'].':'.$config['Port'], $errno, $errstr, 4);
  22. if (!$this->master_link) {
  23. $this->master_link = NULL;
  24. Logger::log(Logger::LOG_WARN, 'Could not connect to DNSd master: ['.$errno.'] '.$errstr);
  25. return true;
  26. }
  27. // send introduction packet
  28. $pkt = $this->localConfig['Name']['_'] . pack('N', time());
  29. $pkt .= sha1($pkt.$config['Signature'], true);
  30. $pkt = 'BEGIN'.$pkt;
  31. fputs($this->master_link, pack('n', strlen($pkt)) . $pkt);
  32. $this->status = 0;
  33. $this->buf = '';
  34. $this->IPC->registerSocketWait($this->master_link, array($this, 'readData'), $foo = array());
  35. }
  36. return true;
  37. }
  38. protected function receivePacket($pkt) {
  39. if ($this->status == 0) {
  40. // check if we got what we want
  41. if ($pkt == 'BAD') {
  42. $this->IPC->removeSocket($this->master_link);
  43. fclose($this->master_link);
  44. Logger::log(Logger::LOG_WARN, 'Connection handshake refused by DNSd master (please check master log for details)');
  45. $this->master_link = NULL;
  46. return;
  47. }
  48. // check stuff about master
  49. $config = $this->localConfig['Master'];
  50. $good_sign = sha1(substr($pkt, 0, -20).$config['Signature'], true);
  51. if ($good_sign != substr($pkt, -20)) {
  52. Logger::log(Logger::LOG_WARN, 'Got bad signature from master, this is fishy!');
  53. $this->IPC->removeSocket($this->master_link);
  54. fclose($this->master_link);
  55. $this->master_link = NULL;
  56. return;
  57. }
  58. // strip signature
  59. $pkt = substr($pkt, 0, -20);
  60. // check timestamp
  61. list(,$stamp) = unpack('N', substr($pkt, -4));
  62. if (abs(time() - $stamp) > 5) {
  63. Logger::log(Logger::LOG_WARN, 'DNSd master is reporting bad timestamp, please look for forged packets and master/slave time synch (hint: install ntpd on both)!');
  64. $this->IPC->removeSocket($this->master_link);
  65. fclose($this->master_link);
  66. $this->master_link = NULL;
  67. return;
  68. }
  69. // check server name
  70. $master = substr($pkt, 0, -4);
  71. if ($master != $config['Name']) {
  72. Logger::log(Logger::LOG_WARN, 'DNSd master is note reporting the same name as the one found in config (hint: pay attention to case)');
  73. $this->IPC->removeSocket($this->master_link);
  74. fclose($this->master_link);
  75. $this->master_link = NULL;
  76. return;
  77. }
  78. $this->status = 1;
  79. // Get most recent change in tables
  80. $recent = $this->db_engine->lastUpdateDate();
  81. $this->sendPkt('DoSync', array($recent));
  82. return;
  83. }
  84. $pkt = @unserialize($pkt);
  85. switch($pkt['type']) {
  86. case 'dispatch':
  87. $data = $pkt['data'];
  88. $this->db_engine->processUpdate($data[0], $data[1]);
  89. break;
  90. case 'pong':
  91. // TODO: compute latency and let user know the master/slave latency :)
  92. }
  93. }
  94. public function domainHit($domain, $hit_count) {
  95. return $this->sendPkt('domainHit', array($domain, $hit_count));
  96. }
  97. protected function sendPkt($cmd, array $params = array()) {
  98. $data = serialize(array($cmd, $params));
  99. if (strlen($data) > 65535) return false;
  100. return fwrite($this->master_link, pack('n', strlen($data)).$data);
  101. }
  102. protected function parseBuffer() {
  103. while(!is_null($this->master_link)) {
  104. if (strlen($this->buf) < 2) break;
  105. list(,$len) = unpack('n', $this->buf);
  106. if (strlen($this->buf) < (2+$len)) break;
  107. $dat = substr($this->buf, 2, $len);
  108. $this->buf = substr($this->buf, $len+2);
  109. $this->receivePacket($dat);
  110. }
  111. }
  112. public function readData() {
  113. $dat = fread($this->master_link, 4096);
  114. if (($dat === false) || ($dat === '')) {
  115. Logger::log(Logger::LOG_WARN, "Lost link with DNSd master");
  116. $this->IPC->removeSocket($this->master_link);
  117. fclose($this->master_link);
  118. $this->master_link = NULL;
  119. }
  120. $this->buf .= $dat;
  121. $this->parseBuffer();
  122. }
  123. public function mainLoop() {
  124. parent::initMainLoop();
  125. $class = relativeclass($this, 'DbEngine');
  126. $this->db_engine = new $class($this, $this->localConfig, $this->IPC);
  127. $this->IPC->createPort('DNSd::DbEngine::'.$this->db_engine->unique(), $this->db_engine);
  128. Timer::addTimer(array($this, 'checkMaster'), 5, $foo = NULL, true);
  129. Timer::addTimer(array($this, 'pingMaster'), 120, $foo = NULL, true);
  130. $this->checkMaster();
  131. while(1) {
  132. $this->IPC->selectSockets(200000);
  133. Timer::processTimers();
  134. }
  135. }
  136. public function shutdown() {
  137. }
  138. }