PageRenderTime 72ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/TimeSync/Ntp.php

https://bitbucket.org/baruffaldi/cms-php-bfcms
PHP | 400 lines | 185 code | 49 blank | 166 comment | 20 complexity | c59d31a3e3bf831a258f0a6c77be21cd MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_TimeSync
  17. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Ntp.php 9488 2008-05-19 20:41:34Z thomas $
  20. */
  21. /**
  22. * Zend_TimeSync_Protocol
  23. */
  24. require_once 'Zend/TimeSync/Protocol.php';
  25. /**
  26. * NTP Protocol handling class
  27. *
  28. * @category Zend
  29. * @package Zend_TimeSync
  30. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. */
  33. class Zend_TimeSync_Ntp extends Zend_TimeSync_Protocol
  34. {
  35. /**
  36. * NTP port number (123) assigned by the Internet Assigned Numbers Authority
  37. *
  38. * @var integer
  39. */
  40. protected $_port = 123;
  41. /**
  42. * NTP class constructor, sets the timeserver and port number
  43. *
  44. * @param string $timeserver Adress of the timeserver to connect to
  45. * @param integer $port (Optional) Port for this timeserver
  46. */
  47. public function __construct($timeserver, $port = 123)
  48. {
  49. $this->_timeserver = 'udp://' . $timeserver;
  50. if (is_null($port) === false) {
  51. $this->_port = $port;
  52. }
  53. }
  54. /**
  55. * Prepare local timestamp for transmission in our request packet
  56. *
  57. * NTP timestamps are represented as a 64-bit fixed-point number, in
  58. * seconds relative to 0000 UT on 1 January 1900. The integer part is
  59. * in the first 32 bits and the fraction part in the last 32 bits
  60. *
  61. * @return string
  62. */
  63. protected function _prepare()
  64. {
  65. $frac = microtime();
  66. $fracba = ($frac & 0xff000000) >> 24;
  67. $fracbb = ($frac & 0x00ff0000) >> 16;
  68. $fracbc = ($frac & 0x0000ff00) >> 8;
  69. $fracbd = ($frac & 0x000000ff);
  70. $sec = (time() + 2208988800);
  71. $secba = ($sec & 0xff000000) >> 24;
  72. $secbb = ($sec & 0x00ff0000) >> 16;
  73. $secbc = ($sec & 0x0000ff00) >> 8;
  74. $secbd = ($sec & 0x000000ff);
  75. // Flags
  76. $nul = chr(0x00);
  77. $nulbyte = $nul . $nul . $nul . $nul;
  78. $ntppacket = chr(0xd9) . $nul . chr(0x0a) . chr(0xfa);
  79. /*
  80. * Root delay
  81. *
  82. * Indicates the total roundtrip delay to the primary reference
  83. * source at the root of the synchronization subnet, in seconds
  84. */
  85. $ntppacket .= $nul . $nul . chr(0x1c) . chr(0x9b);
  86. /*
  87. * Clock Dispersion
  88. *
  89. * Indicates the maximum error relative to the primary reference source at the
  90. * root of the synchronization subnet, in seconds
  91. */
  92. $ntppacket .= $nul . chr(0x08) . chr(0xd7) . chr(0xff);
  93. /*
  94. * ReferenceClockID
  95. *
  96. * Identifying the particular reference clock
  97. */
  98. $ntppacket .= $nulbyte;
  99. /*
  100. * The local time, in timestamp format, at the peer when its latest NTP message
  101. * was sent. Contanis an integer and a fractional part
  102. */
  103. $ntppacket .= chr($secba) . chr($secbb) . chr($secbc) . chr($secbd);
  104. $ntppacket .= chr($fracba) . chr($fracbb) . chr($fracbc) . chr($fracbd);
  105. /*
  106. * The local time, in timestamp format, at the peer. Contains an integer
  107. * and a fractional part.
  108. */
  109. $ntppacket .= $nulbyte;
  110. $ntppacket .= $nulbyte;
  111. /*
  112. * This is the local time, in timestamp format, when the latest NTP message from
  113. * the peer arrived. Contanis an integer and a fractional part.
  114. */
  115. $ntppacket .= $nulbyte;
  116. $ntppacket .= $nulbyte;
  117. /*
  118. * The local time, in timestamp format, at which the
  119. * NTP message departed the sender. Contanis an integer
  120. * and a fractional part.
  121. */
  122. $ntppacket .= chr($secba) . chr($secbb) . chr($secbc) . chr($secbd);
  123. $ntppacket .= chr($fracba) . chr($fracbb) . chr($fracbc) . chr($fracbd);
  124. return $ntppacket;
  125. }
  126. /**
  127. * Reads the data returned from the timeserver
  128. *
  129. * This will return an array with binary data listing:
  130. *
  131. * @return array
  132. * @throws Zend_TimeSync_Exception When timeserver can not be connected
  133. */
  134. protected function _read()
  135. {
  136. $flags = ord(fread($this->_socket, 1));
  137. $info = stream_get_meta_data($this->_socket);
  138. if ($info['timed_out'] === true) {
  139. fclose($this->_socket);
  140. throw new Zend_TimeSync_Exception('could not connect to ' .
  141. "'$this->_timeserver' on port '$this->_port', reason: 'server timed out'");
  142. }
  143. $result = array(
  144. 'flags' => $flags,
  145. 'stratum' => ord(fread($this->_socket, 1)),
  146. 'poll' => ord(fread($this->_socket, 1)),
  147. 'precision' => ord(fread($this->_socket, 1)),
  148. 'rootdelay' => ord(fread($this->_socket, 4)),
  149. 'rootdispersion' => ord(fread($this->_socket, 4)),
  150. 'referenceid' => ord(fread($this->_socket, 4)),
  151. 'referencestamp' => ord(fread($this->_socket, 4)),
  152. 'referencemicro' => ord(fread($this->_socket, 4)),
  153. 'originatestamp' => ord(fread($this->_socket, 4)),
  154. 'originatemicro' => ord(fread($this->_socket, 4)),
  155. 'receivestamp' => ord(fread($this->_socket, 4)),
  156. 'receivemicro' => ord(fread($this->_socket, 4)),
  157. 'transmitstamp' => ord(fread($this->_socket, 4)),
  158. 'transmitmicro' => ord(fread($this->_socket, 4)),
  159. 'clientreceived' => 0
  160. );
  161. $this->_disconnect();
  162. return $result;
  163. }
  164. /**
  165. * Sends the NTP packet to the server
  166. *
  167. * @param string $data Data to send to the timeserver
  168. * @return void
  169. */
  170. protected function _write($data)
  171. {
  172. $this->_connect();
  173. fwrite($this->_socket, $data);
  174. stream_set_timeout($this->_socket, Zend_TimeSync::$options['timeout']);
  175. }
  176. /**
  177. * Extracts the binary data returned from the timeserver
  178. *
  179. * @param string|array $binary Data returned from the timeserver
  180. * @return integer Difference in seconds
  181. */
  182. protected function _extract($binary)
  183. {
  184. /*
  185. * Leap Indicator bit 1100 0000
  186. *
  187. * Code warning of impending leap-second to be inserted at the end of
  188. * the last day of the current month.
  189. */
  190. $leap = ($binary['flags'] & 0xc0) >> 6;
  191. switch($leap) {
  192. case 0:
  193. $this->_info['leap'] = '0 - no warning';
  194. break;
  195. case 1:
  196. $this->_info['leap'] = '1 - last minute has 61 seconds';
  197. break;
  198. case 2:
  199. $this->_info['leap'] = '2 - last minute has 59 seconds';
  200. break;
  201. default:
  202. $this->_info['leap'] = '3 - not syncronised';
  203. break;
  204. }
  205. /*
  206. * Version Number bit 0011 1000
  207. *
  208. * This should be 3 (RFC 1305)
  209. */
  210. $this->_info['version'] = ($binary['flags'] & 0x38) >> 3;
  211. /*
  212. * Mode bit 0000 0111
  213. *
  214. * Except in broadcast mode, an NTP association is formed when two peers
  215. * exchange messages and one or both of them create and maintain an
  216. * instantiation of the protocol machine, called an association.
  217. */
  218. $mode = ($binary['flags'] & 0x07);
  219. switch($mode) {
  220. case 1:
  221. $this->_info['mode'] = 'symetric active';
  222. break;
  223. case 2:
  224. $this->_info['mode'] = 'symetric passive';
  225. break;
  226. case 3:
  227. $this->_info['mode'] = 'client';
  228. break;
  229. case 4:
  230. $this->_info['mode'] = 'server';
  231. break;
  232. case 5:
  233. $this->_info['mode'] = 'broadcast';
  234. break;
  235. default:
  236. $this->_info['mode'] = 'reserved';
  237. break;
  238. }
  239. $ntpserviceid = 'Unknown Stratum ' . $binary['stratum'] . ' Service';
  240. /*
  241. * Reference Clock Identifier
  242. *
  243. * Identifies the particular reference clock.
  244. */
  245. $refid = strtoupper($binary['referenceid']);
  246. switch($binary['stratum']) {
  247. case 0:
  248. if (substr($refid, 0, 3) === 'DCN') {
  249. $ntpserviceid = 'DCN routing protocol';
  250. } else if (substr($refid, 0, 4) === 'NIST') {
  251. $ntpserviceid = 'NIST public modem';
  252. } else if (substr($refid, 0, 3) === 'TSP') {
  253. $ntpserviceid = 'TSP time protocol';
  254. } else if (substr($refid, 0, 3) === 'DTS') {
  255. $ntpserviceid = 'Digital Time Service';
  256. }
  257. break;
  258. case 1:
  259. if (substr($refid, 0, 4) === 'ATOM') {
  260. $ntpserviceid = 'Atomic Clock (calibrated)';
  261. } else if (substr($refid, 0, 3) === 'VLF') {
  262. $ntpserviceid = 'VLF radio';
  263. } else if ($refid === 'CALLSIGN') {
  264. $ntpserviceid = 'Generic radio';
  265. } else if (substr($refid, 0, 4) === 'LORC') {
  266. $ntpserviceid = 'LORAN-C radionavigation';
  267. } else if (substr($refid, 0, 4) === 'GOES') {
  268. $ntpserviceid = 'GOES UHF environment satellite';
  269. } else if (substr($refid, 0, 3) === 'GPS') {
  270. $ntpserviceid = 'GPS UHF satellite positioning';
  271. }
  272. break;
  273. default:
  274. $ntpserviceid = ord(substr($binary['referenceid'], 0, 1));
  275. $ntpserviceid .= '.';
  276. $ntpserviceid .= ord(substr($binary['referenceid'], 1, 1));
  277. $ntpserviceid .= '.';
  278. $ntpserviceid .= ord(substr($binary['referenceid'], 2, 1));
  279. $ntpserviceid .= '.';
  280. $ntpserviceid .= ord(substr($binary['referenceid'], 3, 1));
  281. break;
  282. }
  283. $this->_info['ntpid'] = $ntpserviceid;
  284. /*
  285. * Stratum
  286. *
  287. * Indicates the stratum level of the local clock
  288. */
  289. switch($binary['stratum']) {
  290. case 0:
  291. $this->_info['stratum'] = 'undefined';
  292. break;
  293. case 1:
  294. $this->_info['stratum'] = 'primary reference';
  295. break;
  296. default:
  297. $this->_info['stratum'] = 'secondary reference';
  298. break;
  299. }
  300. /*
  301. * Indicates the total roundtrip delay to the primary reference source at the
  302. * root of the synchronization subnet, in seconds.
  303. *
  304. * Both positive and negative values, depending on clock precision and skew, are
  305. * possible.
  306. */
  307. $this->_info['rootdelay'] = $binary['rootdelay'] >> 15;
  308. $this->_info['rootdelayfrac'] = ($binary['rootdelay'] << 17) >> 17;
  309. /*
  310. * Indicates the maximum error relative to the primary reference source at the
  311. * root of the synchronization subnet, in seconds.
  312. *
  313. * Only positive values greater than zero are possible.
  314. */
  315. $this->_info['rootdispersion'] = $binary['rootdispersion'] >> 15;
  316. $this->_info['rootdispersionfrac'] = ($binary['rootdispersion'] << 17) >> 17;
  317. /*
  318. * The local time, in timestamp format, at the peer
  319. * when its latest NTP message was sent.
  320. */
  321. $original = (float) $binary['originatestamp'];
  322. $original += (float) ($binary['originatemicro'] / 4294967296);
  323. /*
  324. * The local time, in timestamp format, when the latest
  325. * NTP message from the peer arrived.
  326. */
  327. $received = (float) $binary['receivestamp'];
  328. $received += (float) ($binary['receivemicro'] / 4294967296);
  329. /*
  330. * The local time, in timestamp format, at which the
  331. * NTP message departed the sender.
  332. */
  333. $transmit = (float) $binary['transmitstamp'];
  334. $transmit += (float) ($binary['transmitmicro'] / 4294967296);
  335. /*
  336. * The roundtrip delay of the peer clock relative to the local clock
  337. * over the network path between them, in seconds.
  338. *
  339. * Note that this variable can take on both positive and negative values,
  340. * depending on clock precision and skew-error accumulation.
  341. */
  342. $roundtrip = ($binary['clientreceived'] - $original);
  343. $roundtrip -= ($transmit - $received);
  344. $this->_info['roundtrip'] = ($roundtrip / 2);
  345. // The offset of the peer clock relative to the local clock, in seconds.
  346. $offset = ($received - $original + $transmit - $binary['clientreceived']);
  347. $this->_info['offset'] = ($offset / 2);
  348. $time = (time() - $this->_info['offset']);
  349. return $time;
  350. }
  351. }