PageRenderTime 146ms CodeModel.GetById 51ms app.highlight 52ms RepoModel.GetById 38ms app.codeStats 0ms

/library/Zend/TimeSync/Ntp.php

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