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

/code/classes/pinetd/TCP/Client.class.php

https://github.com/blekkzor/pinetd2
PHP | 242 lines | 191 code | 28 blank | 23 comment | 29 complexity | 5fcc90f333b88af9ed09a6badc98d89a MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /* Portable INET daemon v2 in PHP
  3. * Copyright (C) 2007 Mark Karpeles <mark@kinoko.fr>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. namespace pinetd\TCP;
  20. use pinetd\Logger;
  21. class Client extends \pinetd\ProcessChild {
  22. protected $fd;
  23. protected $peer;
  24. private $send_end = '';
  25. private $debug_fd = NULL;
  26. protected $buf = '';
  27. protected $ok = true;
  28. protected $protocol = 'tcp';
  29. public function __construct($fd, $peer, $parent, $protocol) {
  30. $this->fd = $fd;
  31. if (is_array($peer)) {
  32. $this->peer = $peer;
  33. } else {
  34. $this->peer = explode(':', $peer); // ip:port TODO: handle ipv6
  35. }
  36. $this->protocol = $protocol;
  37. $debug = $parent->getDebug();
  38. if (!is_null($debug)) {
  39. // we got debugging
  40. $file = $debug.date('Ymd-His_').$this->peer[0].'_'.microtime(true).'.log';
  41. $fd = fopen($file, 'w');
  42. if ($fd)
  43. $this->debug_fd = $fd;
  44. } else {
  45. $this->debug_fd = NULL;
  46. }
  47. parent::__construct($parent);
  48. // var_dump(stream_filter_register('pinetd.autossl', 'pinetd\\TCP\\AutoSSL'));
  49. // var_dump(stream_filter_prepend($this->fd, 'pinetd.autossl', STREAM_FILTER_READ));
  50. }
  51. public function doResolve() {
  52. if (!is_null($this->dns)) return;
  53. $this->peer[2] = gethostbyaddr($this->peer[0]);
  54. $this->debug('Resolved to: '.$this->peer[2]);
  55. }
  56. protected function debug($msg) {
  57. if ($this->debug_fd)
  58. fwrite($this->debug_fd, '***** '.$msg."\n");
  59. }
  60. public function shutdown() {
  61. // (void)
  62. }
  63. public function getHostName() {
  64. return $this->peer[2];
  65. }
  66. public function setMsgEnd($str) {
  67. $this->send_end = $str;
  68. }
  69. public function sendMsg($msg) {
  70. if (!$this->ok) return false;
  71. if ($this->debug_fd)
  72. fwrite($this->debug_fd, '> '.$msg."\n");
  73. return fwrite($this->fd, $msg . $this->send_end);
  74. }
  75. public function close() {
  76. Logger::log(Logger::LOG_DEBUG, 'Client from '.$this->peer[0].' is being closed');
  77. $this->ok = false;
  78. $this->IPC->killSelf($this->fd);
  79. return fclose($this->fd);
  80. }
  81. protected function parseLine($lin) {
  82. $lin = rtrim($lin); // strip potential \r and \n
  83. $argv = preg_split('/\s+/', $lin);
  84. $fullarg = ltrim(substr($lin, strlen($argv[0])));
  85. $cmd = '_cmd_'.strtolower($argv[0]);
  86. if (!method_exists($this, $cmd)) $cmd = '_cmd_default';
  87. return $this->$cmd($argv, $cmd, $fullarg);
  88. }
  89. protected function parseBuffer() {
  90. while($this->ok) {
  91. $pos = strpos($this->buf, "\n");
  92. if ($pos === false) break;
  93. $pos++;
  94. $lin = substr($this->buf, 0, $pos);
  95. $this->buf = substr($this->buf, $pos);
  96. if ($this->debug_fd)
  97. fwrite($this->debug_fd, '< '.rtrim($lin)."\n");
  98. $this->parseLine($lin);
  99. }
  100. $this->setProcessStatus(); // back to idle
  101. }
  102. // overload this to add an action on timeout (eg. sending a msg to client). Please return true
  103. public function socketTimedOut() {
  104. Logger::log(Logger::LOG_DEBUG, 'Socket timed out, closing');
  105. $this->close();
  106. return true;
  107. }
  108. protected function pullDataFromSocket() {
  109. $res = fread($this->fd, 8192);
  110. return $res;
  111. }
  112. public function readData() {
  113. $dat = $this->pullDataFromSocket();
  114. if (($dat === false) || ($dat === '')) {
  115. Logger::log(Logger::LOG_INFO, 'Lost client from '.$this->peer[0]);
  116. $this->IPC->killSelf($this->fd);
  117. $this->ok = false;
  118. return;
  119. }
  120. $this->buf .= $dat;
  121. $this->parseBuffer();
  122. }
  123. public function readLen($len) {
  124. while(strlen($this->buf) < $len) {
  125. $dat = $this->pullDataFromSocket();
  126. if (($dat === false) || ($dat === '')) {
  127. Logger::log(Logger::LOG_INFO, 'Lost client from '.$this->peer[0]);
  128. $this->IPC->killSelf($this->fd);
  129. $this->ok = false;
  130. throw new Exception('Client lost');
  131. }
  132. $this->buf .= $dat;
  133. }
  134. $res = substr($this->buf, 0, $len);
  135. $this->buf = substr($this->buf, $len);
  136. return $res;
  137. }
  138. public function readTmpFd($len) {
  139. $fd = fopen('php://temp', 'r+');
  140. $pos = 0;
  141. if (strlen($this->buf) > 0) {
  142. if (strlen($this->buf) > $len) { // already got enough data
  143. fwrite($fd, substr($this->buf, 0, $len));
  144. $this->buf = substr($this->buf, $len);
  145. return $fd;
  146. }
  147. // need more data
  148. $pos = strlen($this->buf);
  149. fwrite($fd, $this->buf);
  150. $this->buf = '';
  151. }
  152. while($pos < $len) {
  153. $dat = $this->pullDataFromSocket();
  154. if (($dat === false) || ($dat === '')) {
  155. Logger::log(Logger::LOG_INFO, 'Lost client from '.$this->peer[0]);
  156. $this->IPC->killSelf($this->fd);
  157. $this->ok = false;
  158. throw new Exception('Client lost');
  159. }
  160. $rem = $len - $pos;
  161. if (strlen($dat) >= $rem) {
  162. fwrite($fd, substr($dat, 0, $rem));
  163. $this->buf = (string)substr($dat, $rem);
  164. return $fd;
  165. }
  166. fwrite($fd, $dat);
  167. $pos += strlen($dat);
  168. }
  169. }
  170. public function readLine() {
  171. $dat = $this->pullDataFromSocket();
  172. if (($dat === false) || ($dat === '')) {
  173. Logger::log(Logger::LOG_INFO, 'Lost client from '.$this->peer[0]);
  174. $this->IPC->killSelf($this->fd);
  175. $this->ok = false;
  176. throw new Exception('Client lost');
  177. }
  178. $this->buf .= $dat;
  179. $pos = strpos($this->buf, "\n");
  180. if ($pos === false) {
  181. $res = $this->buf;
  182. $this->buf = '';
  183. return $res;
  184. }
  185. $pos++;
  186. $lin = substr($this->buf, 0, $pos);
  187. $this->buf = substr($this->buf, $pos);
  188. return $lin;
  189. }
  190. protected function setProcessStatus($msg = '') {
  191. if (!defined('PINETD_GOT_PROCTITLE')) return;
  192. if (!$msg) $msg = 'idle';
  193. if ((isset($this->peer[2])) && ($this->peer[0] != $this->peer[2])) {
  194. setproctitle('[' . $this->peer[0] . '] ' . get_class($this) . ': ' . $msg . ' (' . $this->peer[2].')');
  195. return;
  196. }
  197. setproctitle('['.$this->peer[0].'] ' . get_class($this) . ': ' . $msg);
  198. }
  199. public function mainLoop($IPC) {
  200. $this->IPC = $IPC;
  201. $this->IPC->setParent($this);
  202. $this->IPC->registerSocketWait($this->fd, array($this, 'readData'), $foo = array());
  203. $this->IPC->setTimeOut($this->fd, 3600, array($this, 'socketTimedOut'), $foo = array());
  204. $this->setProcessStatus('resolving');
  205. $this->doResolve();
  206. $this->sendBanner();
  207. $this->setProcessStatus();
  208. while($this->ok) {
  209. $IPC->selectSockets(200000);
  210. $this->processTimers();
  211. }
  212. exit;
  213. }
  214. }