PageRenderTime 53ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/test/pmaild2_admin.php

https://github.com/blekkzor/pinetd2
PHP | 244 lines | 191 code | 41 blank | 12 comment | 30 complexity | 71061e31c5e778f10bd2bb4dde232009 MD5 | raw file
Possible License(s): GPL-2.0
  1. #!../php/php
  2. <?php
  3. date_default_timezone_set('GMT');
  4. class PMaild2 {
  5. private $fd;
  6. private $seq;
  7. private $uuid;
  8. public function __construct($host, $port, $uuid, $key) {
  9. $sock = fsockopen('ssl://'.$host, $port, $errno, $errstr, 10);
  10. if (!$sock) throw new Exception('Failed to connect: '.$errstr);
  11. $handshake = fread($sock, 44); // remote id
  12. // check uuid
  13. $uuidb = pack('H*', str_replace('-', '', $uuid));
  14. if (substr($handshake, 0, 16) != $uuidb) throw new Exception('Peer didn\'t identify correctly');
  15. // check timestamp drift
  16. $stamp = unpack('N2', substr($handshake, 16, 8));
  17. $stamp[1] ^= $stamp[2];
  18. $stamp = (($stamp[1] << 32) | $stamp[2]) / 1000000;
  19. $offset = abs(microtime(true)-$stamp);
  20. if ($offset > 0.5) throw new Exception('Time drift is over 0.5 secs ('.$offset.'), please resync servers');
  21. // check signature
  22. $sign = sha1(pack('H*', $key).substr($handshake, 0, 24), true);
  23. if ($sign != substr($handshake, 24)) throw new Exception('Bad signature');
  24. // send our own packet
  25. $stamp = (int)round(microtime(true)*1000000);
  26. $stamp = pack('NN', (($stamp >> 32) & 0xffffffff) ^ ($stamp & 0xffffffff), $stamp & 0xffffffff);
  27. $handshake = str_repeat("\0", 16).$stamp;
  28. $handshake .= sha1(pack('H*', $key).$handshake, true);
  29. fwrite($sock, $handshake);
  30. $this->fd = $sock;
  31. $this->seq = 0;
  32. $this->uuid = $uuid;
  33. }
  34. protected function _sendPacket(array $pkt) {
  35. $pkt = json_encode($pkt);
  36. if (strlen($pkt) > 65535) throw new Exception('Error: packet is too big!');
  37. return fwrite($this->fd, pack('n', strlen($pkt)).$pkt);
  38. }
  39. protected function _readPacket() {
  40. $len = fread($this->fd, 2);
  41. if (feof($this->fd)) throw new Exception('Connection interrupt!');
  42. list(,$len) = unpack('n', $len);
  43. if ($len == 0) throw new Exception('Invalid packet!');
  44. $data = fread($this->fd, $len);
  45. if (strlen($data) != $len) throw new Exception('Could not read enough data (expect: '.$len.' got: '.strlen($data).')');
  46. return json_decode($data, true);
  47. }
  48. protected function _waitAck($ack) {
  49. while(1) {
  50. $pkt = $this->_readPacket();
  51. if (!isset($pkt['ack'])) continue;
  52. if ($pkt['ack'] == $ack) return $pkt['res'];
  53. }
  54. }
  55. protected function _event($evt, array $ref, $fd = NULL) {
  56. ksort($ref);
  57. $pkt = array(
  58. 'evt' => $evt,
  59. 'ref' => http_build_query($ref, '', '&'),
  60. 'stp' => (int)round(microtime(true)*1000000), // magic stamp
  61. );
  62. if (!is_null($fd)) {
  63. fseek($fd, 0, SEEK_END);
  64. $pkt['dat'] = ftell($fd);
  65. }
  66. $ack = $this->seq++;
  67. $pkt = array(
  68. 'typ' => 'log',
  69. 'pkt' => $pkt,
  70. 'ack' => $ack,
  71. );
  72. $this->_sendPacket($pkt);
  73. if (!is_null($fd)) {
  74. // send extra data too
  75. rewind($fd);
  76. stream_copy_to_stream($fd, $this->fd);
  77. }
  78. return $this->_waitAck($ack);
  79. }
  80. protected function _query($type, $ref = null) {
  81. if (!is_null($ref)) ksort($ref);
  82. $ack = $this->seq++;
  83. $pkt = array(
  84. 'qry' => $type,
  85. );
  86. if (!is_null($ref)) $pkt['ref'] = http_build_query($ref, '', '&');
  87. $pkt = array(
  88. 'typ' => 'qry',
  89. 'pkt' => $pkt,
  90. 'ack' => $ack,
  91. );
  92. $this->_sendPacket($pkt);
  93. return $this->_waitAck($ack);
  94. }
  95. public function askUuid() {
  96. // ask remote peer to be kind enough to produce an uuid and send it to us
  97. return $this->_query('uuid');
  98. }
  99. public function createNode($uuid, $ip, $port, $key) {
  100. // connect to the new node first
  101. $info = $this->getNode($this->uuid);
  102. if (!$info) return false;
  103. try {
  104. $node = new self($ip, $port, $uuid, $key);
  105. } catch(Exception $e) {
  106. return false;
  107. }
  108. // the node might have a wrong ip/port for itself
  109. $node_info = stream_socket_get_name($this->fd, true);
  110. $node_info = explode(':', $node_info);
  111. $info['ip'] = $node_info[0];
  112. $info['port'] = $node_info[1];
  113. // create an entry for us on the new node
  114. if (!$node->subCreateNode($info['node'], $info['ip'], $info['port'], $info['key'])) return false;
  115. // and add the node to us
  116. return $this->subCreateNode($uuid, $ip, $port, $key);
  117. }
  118. private function subCreateNode($uuid, $ip, $port, $key) {
  119. $fd = fopen('php://temp', 'r+');
  120. fwrite($fd, json_encode(array('ip' => $ip, 'port' => $port, 'key' => $key)));
  121. $res = $this->_event('node/add', array('node' => $uuid), $fd);
  122. fclose($fd);
  123. return $res;
  124. }
  125. public function getNodes() {
  126. return $this->_query('node');
  127. }
  128. public function getNode($node) {
  129. $res = $this->_query('node', array('node' => $node));
  130. if (isset($res[$node])) return $res[$node];
  131. return NULL;
  132. }
  133. public function createStore($uuid = null) {
  134. if (is_null($uuid)) $uuid = $this->askUuid();
  135. if (!$this->_event('store/add', array('store' => $uuid))) return false;
  136. return $uuid;
  137. }
  138. public function getStores() {
  139. return $this->_query('store');
  140. }
  141. public function getStore($store) {
  142. return $this->_query('store', array('store' => $store));
  143. }
  144. public function createDomain($domain, $store) {
  145. $fd = fopen('php://temp', 'r+');
  146. fwrite($fd, json_encode(array('store' => $store)));
  147. $res = $this->_event('domain/add', array('domain' => $domain), $fd);
  148. fclose($fd);
  149. return $res;
  150. }
  151. public function getDomains() {
  152. return $this->_query('domain');
  153. }
  154. public function getDomain($domain) {
  155. $res = $this->_query('domain', array('domain' => $domain));
  156. foreach($res as $sres) return $sres;
  157. return $res;
  158. }
  159. public function createAccount($store, array $properties = array(), $uuid = NULL) {
  160. if (is_null($uuid)) $uuid = $this->askUuid();
  161. $fd = fopen('php://temp', 'r+');
  162. fwrite($fd, json_encode($properties));
  163. if (!$this->_event('account/add', array('store' => $store, 'account' => $uuid), $fd)) return false;
  164. fclose($fd);
  165. return $uuid;
  166. }
  167. public function createLogin($store, $login, $type, $target) {
  168. $fd = fopen('php://temp', 'r+');
  169. fwrite($fd, json_encode(array('type' => $type, 'target' => $target)));
  170. $res = $this->_event('login/add', array('store' => $store, 'login' => $login), $fd);
  171. fclose($fd);
  172. return $res;
  173. }
  174. public function createLoginToAccount($store, $login, $account) {
  175. return $this->createLogin($store, $login, 'account', $account);
  176. }
  177. public function getLogins($store) {
  178. return $this->_query('login', array('store' => $store));
  179. }
  180. public function getLogin($store, $login) {
  181. $res = $this->_query('login', array('store' => $store, 'login' => $login));
  182. foreach($res as $sres) return $sres;
  183. return $res;
  184. }
  185. }
  186. $adm = new PMaild2('127.0.0.1',10006,'eb720e74-223d-4660-b83f-852a1de7040e','5726a8e0dbf1f65e443de80c5dbe28c2fcced407aa70ff241017458cbe7474e1');
  187. //var_dump($adm->listStores());
  188. $domain = $adm->getDomain('example.com');
  189. if ($domain) {
  190. $store = $domain['store'];
  191. } else {
  192. $store = $adm->createStore();
  193. var_dump($adm->createDomain('example.com', $store));
  194. }
  195. $login = $adm->getLogin($store, 'test');
  196. if (!$login) {
  197. $account = $adm->createAccount($store, array('password' => crypt('test')));
  198. var_dump($adm->createLoginToAccount($store, 'test', $account));
  199. } else {
  200. var_dump($login);
  201. }
  202. var_dump($adm->getNodes());
  203. var_dump($adm->createNode('5880f24b-0f87-4abd-9d1f-c9f124bbf939', '127.0.0.1', 20006, 'f799839ef564b5086907ffd03024d161dd530088b0dfa25e7e9ceb34983fb045'));