PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/includes/net/dns2/socket/streams.php

https://bitbucket.org/speedealing/speedealing
PHP | 393 lines | 165 code | 66 blank | 162 comment | 35 complexity | 7b76db59d8b32cec288ac46a8bee7ae6 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * DNS Library for handling lookups and updates.
  5. *
  6. * PHP Version 5
  7. *
  8. * Copyright (c) 2010, Mike Pultz <mike@mikepultz.com>.
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. *
  15. * * Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. *
  18. * * Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in
  20. * the documentation and/or other materials provided with the
  21. * distribution.
  22. *
  23. * * Neither the name of Mike Pultz nor the names of his contributors
  24. * may be used to endorse or promote products derived from this
  25. * software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  30. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  31. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  33. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  35. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * @category Networking
  41. * @package Net_DNS2
  42. * @author Mike Pultz <mike@mikepultz.com>
  43. * @copyright 2010 Mike Pultz <mike@mikepultz.com>
  44. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  45. * @version SVN: $Id: Streams.php 168 2012-09-13 02:01:29Z mike.pultz $
  46. * @link http://pear.php.net/package/Net_DNS2
  47. * @since File available since Release 0.6.0
  48. *
  49. */
  50. /**
  51. * Socket handling class using the PHP Streams
  52. *
  53. * The sockets extension is faster than the stream functions in PHP, but it's
  54. * not standard. So if the extension is loaded, then the Net_DNS_Socket_Sockets
  55. * class it used, otherwise, this class it used.
  56. *
  57. * @category Networking
  58. * @package Net_DNS2
  59. * @author Mike Pultz <mike@mikepultz.com>
  60. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  61. * @link http://pear.php.net/package/Net_DNS2
  62. * @see Net_DNS2_Socket
  63. *
  64. */
  65. class Net_DNS2_Socket_Streams extends Net_DNS2_Socket
  66. {
  67. private $_context;
  68. /**
  69. * opens a socket connection to the DNS server
  70. *
  71. * @return boolean
  72. * @access public
  73. *
  74. */
  75. public function open()
  76. {
  77. //
  78. // create a list of options for the context
  79. //
  80. $opts = array('socket' => array());
  81. //
  82. // bind to a local IP/port if it's set
  83. //
  84. if (strlen($this->local_host) > 0) {
  85. $opts['socket']['bindto'] = $this->local_host;
  86. if ($this->local_port > 0) {
  87. $opts['socket']['bindto'] .= ':' . $this->local_port;
  88. }
  89. }
  90. //
  91. // create the context
  92. //
  93. $this->_context = @stream_context_create($opts);
  94. //
  95. // create socket
  96. //
  97. $errno;
  98. $errstr;
  99. switch($this->type) {
  100. case Net_DNS2_Socket::SOCK_STREAM:
  101. if (Net_DNS2::isIPv4($this->host) == true) {
  102. $this->sock = @stream_socket_client(
  103. 'tcp://' . $this->host . ':' . $this->port,
  104. $errno, $errstr, $this->timeout,
  105. STREAM_CLIENT_CONNECT, $this->_context
  106. );
  107. } else if (Net_DNS2::isIPv6($this->host) == true) {
  108. $this->sock = @stream_socket_client(
  109. 'tcp://[' . $this->host . ']:' . $this->port,
  110. $errno, $errstr, $this->timeout,
  111. STREAM_CLIENT_CONNECT, $this->_context
  112. );
  113. } else {
  114. $this->last_error = 'invalid address type: ' . $this->host;
  115. return false;
  116. }
  117. break;
  118. case Net_DNS2_Socket::SOCK_DGRAM:
  119. if (Net_DNS2::isIPv4($this->host) == true) {
  120. $this->sock = @stream_socket_client(
  121. 'udp://' . $this->host . ':' . $this->port,
  122. $errno, $errstr, $this->timeout,
  123. STREAM_CLIENT_CONNECT, $this->_context
  124. );
  125. } else if (Net_DNS2::isIPv6($this->host) == true) {
  126. $this->sock = @stream_socket_client(
  127. 'udp://[' . $this->host . ']:' . $this->port,
  128. $errno, $errstr, $this->timeout,
  129. STREAM_CLIENT_CONNECT, $this->_context
  130. );
  131. } else {
  132. $this->last_error = 'invalid address type: ' . $this->host;
  133. return false;
  134. }
  135. break;
  136. default:
  137. $this->last_error = 'Invalid socket type: ' . $this->type;
  138. return false;
  139. }
  140. if ($this->sock === false) {
  141. $this->last_error = $errstr;
  142. return false;
  143. }
  144. //
  145. // set it to non-blocking and set the timeout
  146. //
  147. @stream_set_blocking($this->sock, 0);
  148. @stream_set_timeout($this->sock, $this->timeout);
  149. return true;
  150. }
  151. /**
  152. * closes a socket connection to the DNS server
  153. *
  154. * @return boolean
  155. * @access public
  156. *
  157. */
  158. public function close()
  159. {
  160. if (is_resource($this->sock) === true) {
  161. @fclose($this->sock);
  162. }
  163. return true;
  164. }
  165. /**
  166. * writes the given string to the DNS server socket
  167. *
  168. * @param string $data a binary packed DNS packet
  169. *
  170. * @return boolean
  171. * @access public
  172. *
  173. */
  174. public function write($data)
  175. {
  176. $length = strlen($data);
  177. if ($length == 0) {
  178. $this->last_error = 'empty data on write()';
  179. return false;
  180. }
  181. $read = null;
  182. $write = array($this->sock);
  183. $except = null;
  184. //
  185. // select on write
  186. //
  187. switch(@stream_select($read, $write, $except, $this->timeout)) {
  188. case false:
  189. $this->last_error = 'failed on stream_select()';
  190. return false;
  191. break;
  192. case 0:
  193. return false;
  194. break;
  195. default:
  196. ;
  197. }
  198. //
  199. // if it's a TCP socket, then we need to packet and send the length of the
  200. // data as the first 16bit of data.
  201. //
  202. if ($this->type == Net_DNS2_Socket::SOCK_STREAM) {
  203. $s = chr($length >> 8) . chr($length);
  204. if (@fwrite($this->sock, $s) === false) {
  205. $this->last_error = 'failed to fwrite() 16bit length';
  206. return false;
  207. }
  208. }
  209. //
  210. // write the data to the socket
  211. //
  212. $size = @fwrite($this->sock, $data);
  213. if ( ($size === false) || ($size != $length) ) {
  214. $this->last_error = 'failed to fwrite() packet';
  215. return false;
  216. }
  217. return true;
  218. }
  219. /**
  220. * reads a response from a DNS server
  221. *
  222. * @param integer &$size the size of the DNS packet read is passed back
  223. *
  224. * @return mixed returns the data on success and false on error
  225. * @access public
  226. *
  227. */
  228. public function read(&$size)
  229. {
  230. $read = array($this->sock);
  231. $write = null;
  232. $except = null;
  233. //
  234. // make sure our socket is non-blocking
  235. //
  236. @stream_set_blocking($this->sock, 0);
  237. //
  238. // select on read
  239. //
  240. switch(stream_select($read, $write, $except, $this->timeout)) {
  241. case false:
  242. $this->last_error = 'error on stream_select()';
  243. return false;
  244. break;
  245. case 0:
  246. return false;
  247. break;
  248. default:
  249. ;
  250. }
  251. $data = '';
  252. $length = Net_DNS2_Lookups::DNS_MAX_UDP_SIZE;
  253. //
  254. // if it's a TCP socket, then the first two bytes is the length of the DNS
  255. // packet- we need to read that off first, then use that value for the
  256. // packet read.
  257. //
  258. if ($this->type == Net_DNS2_Socket::SOCK_STREAM) {
  259. if (($data = fread($this->sock, 2)) === false) {
  260. $this->last_error = 'failed on fread() for data length';
  261. return false;
  262. }
  263. $length = ord($data[0]) << 8 | ord($data[1]);
  264. if ($length < Net_DNS2_Lookups::DNS_HEADER_SIZE) {
  265. return false;
  266. }
  267. }
  268. //
  269. // at this point, we know that there is data on the socket to be read,
  270. // because we've already extracted the length from the first two bytes.
  271. //
  272. // so the easiest thing to do, is just turn off socket blocking, and
  273. // wait for the data.
  274. //
  275. @stream_set_blocking($this->sock, 1);
  276. //
  277. // read the data from the socket
  278. //
  279. $data = '';
  280. //
  281. // the streams socket is weird for TCP sockets; it doesn't seem to always
  282. // return all the data properly; but the looping code I added broke UDP
  283. // packets- my fault-
  284. //
  285. // the sockets library works much better.
  286. //
  287. if ($this->type == Net_DNS2_Socket::SOCK_STREAM) {
  288. $chunk = '';
  289. $chunk_size = $length;
  290. //
  291. // loop so we make sure we read all the data
  292. //
  293. while (1) {
  294. $chunk = fread($this->sock, $chunk_size);
  295. if ($chunk === false) {
  296. $this->last_error = 'failed on fread() for data';
  297. return false;
  298. }
  299. $data .= $chunk;
  300. $chunk_size -= strlen($chunk);
  301. if (strlen($data) >= $length) {
  302. break;
  303. }
  304. }
  305. //
  306. // if it's UDP, ti's a single fixed-size frame, and the streams library
  307. // doesn't seem to have a problem reading it.
  308. //
  309. } else {
  310. $data = fread($this->sock, $length);
  311. if ($length === false) {
  312. $this->last_error = 'failed on fread() for data';
  313. return false;
  314. }
  315. }
  316. $size = strlen($data);
  317. return $data;
  318. }
  319. }
  320. /*
  321. * Local variables:
  322. * tab-width: 4
  323. * c-basic-offset: 4
  324. * c-hanging-comment-ender-p: nil
  325. * End:
  326. */
  327. ?>