PageRenderTime 135ms CodeModel.GetById 80ms app.highlight 20ms RepoModel.GetById 31ms app.codeStats 0ms

/library/Zend/TimeSync/Ntp.php

https://bitbucket.org/fabiancarlos/feature_seguimentos
PHP | 431 lines | 210 code | 49 blank | 172 comment | 20 complexity | ffc3d3cf0ae3bab8402b8d0d484f2d12 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-2011 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 23775 2011-03-01 17:25:24Z ralph $
 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-2011 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 ($port !== null) {
 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     * Calculates a 32bit integer
143     *
144     * @param string $input
145     * @return integer
146     */
147    protected function _getInteger($input)
148    {
149        $f1  = str_pad(ord($input[0]), 2, '0', STR_PAD_LEFT);
150        $f1 .= str_pad(ord($input[1]), 2, '0', STR_PAD_LEFT);
151        $f1 .= str_pad(ord($input[2]), 2, '0', STR_PAD_LEFT);
152        $f1 .= str_pad(ord($input[3]), 2, '0', STR_PAD_LEFT);
153        return (int) $f1;
154    }
155
156    /**
157     * Calculates a 32bit signed fixed point number
158     *
159     * @param string $input
160     * @return float
161     */
162    protected function _getFloat($input)
163    {
164        $f1  = str_pad(ord($input[0]), 2, '0', STR_PAD_LEFT);
165        $f1 .= str_pad(ord($input[1]), 2, '0', STR_PAD_LEFT);
166        $f1 .= str_pad(ord($input[2]), 2, '0', STR_PAD_LEFT);
167        $f1 .= str_pad(ord($input[3]), 2, '0', STR_PAD_LEFT);
168        $f2  = $f1 >> 17;
169        $f3  = ($f1 & 0x0001FFFF);
170        $f1  = $f2 . '.' . $f3;
171        return (float) $f1;
172    }
173
174    /**
175     * Calculates a 64bit timestamp
176     *
177     * @param string $input
178     * @return float
179     */
180    protected function _getTimestamp($input)
181    {
182        $f1  = (ord($input[0]) * pow(256, 3));
183        $f1 += (ord($input[1]) * pow(256, 2));
184        $f1 += (ord($input[2]) * pow(256, 1));
185        $f1 += (ord($input[3]));
186        $f1 -= 2208988800;
187
188        $f2  = (ord($input[4]) * pow(256, 3));
189        $f2 += (ord($input[5]) * pow(256, 2));
190        $f2 += (ord($input[6]) * pow(256, 1));
191        $f2 += (ord($input[7]));
192
193        return (float) ($f1 . "." . $f2);
194    }
195
196    /**
197     * Reads the data returned from the timeserver
198     *
199     * This will return an array with binary data listing:
200     *
201     * @return array
202     * @throws Zend_TimeSync_Exception When timeserver can not be connected
203     */
204    protected function _read()
205    {
206        $flags = ord(fread($this->_socket, 1));
207        $info  = stream_get_meta_data($this->_socket);
208
209        if ($info['timed_out'] === true) {
210            fclose($this->_socket);
211            throw new Zend_TimeSync_Exception('could not connect to ' .
212                "'$this->_timeserver' on port '$this->_port', reason: 'server timed out'");
213        }
214
215        $result = array(
216            'flags'          => $flags,
217            'stratum'        => ord(fread($this->_socket, 1)),
218            'poll'           => ord(fread($this->_socket, 1)),
219            'precision'      => ord(fread($this->_socket, 1)),
220            'rootdelay'      => $this->_getFloat(fread($this->_socket, 4)),
221            'rootdispersion' => $this->_getFloat(fread($this->_socket, 4)),
222            'referenceid'    => fread($this->_socket, 4),
223            'referencestamp' => $this->_getTimestamp(fread($this->_socket, 8)),
224            'originatestamp' => $this->_getTimestamp(fread($this->_socket, 8)),
225            'receivestamp'   => $this->_getTimestamp(fread($this->_socket, 8)),
226            'transmitstamp'  => $this->_getTimestamp(fread($this->_socket, 8)),
227            'clientreceived' => microtime(true)
228        );
229
230        $this->_disconnect();
231        return $result;
232    }
233
234    /**
235     * Sends the NTP packet to the server
236     *
237     * @param  string $data Data to send to the timeserver
238     * @return void
239     */
240    protected function _write($data)
241    {
242        $this->_connect();
243
244        fwrite($this->_socket, $data);
245        stream_set_timeout($this->_socket, Zend_TimeSync::$options['timeout']);
246    }
247
248    /**
249     * Extracts the binary data returned from the timeserver
250     *
251     * @param  string|array $binary Data returned from the timeserver
252     * @return integer Difference in seconds
253     */
254    protected function _extract($binary)
255    {
256        /*
257         * Leap Indicator bit 1100 0000
258         *
259         * Code warning of impending leap-second to be inserted at the end of
260         * the last day of the current month.
261         */
262        $leap = ($binary['flags'] & 0xc0) >> 6;
263        switch($leap) {
264            case 0:
265                $this->_info['leap'] = '0 - no warning';
266                break;
267
268            case 1:
269                $this->_info['leap'] = '1 - last minute has 61 seconds';
270                break;
271
272            case 2:
273                $this->_info['leap'] = '2 - last minute has 59 seconds';
274                break;
275
276            default:
277                $this->_info['leap'] = '3 - not syncronised';
278                break;
279        }
280
281        /*
282         * Version Number bit 0011 1000
283         *
284         * This should be 3 (RFC 1305)
285         */
286        $this->_info['version'] = ($binary['flags'] & 0x38) >> 3;
287
288        /*
289         * Mode bit 0000 0111
290         *
291         * Except in broadcast mode, an NTP association is formed when two peers
292         * exchange messages and one or both of them create and maintain an
293         * instantiation of the protocol machine, called an association.
294         */
295        $mode = ($binary['flags'] & 0x07);
296        switch($mode) {
297            case 1:
298                $this->_info['mode'] = 'symetric active';
299                break;
300
301            case 2:
302                $this->_info['mode'] = 'symetric passive';
303                break;
304
305            case 3:
306                $this->_info['mode'] = 'client';
307                break;
308
309            case 4:
310                $this->_info['mode'] = 'server';
311                break;
312
313            case 5:
314                $this->_info['mode'] = 'broadcast';
315                break;
316
317            default:
318                $this->_info['mode'] = 'reserved';
319                break;
320        }
321
322        $ntpserviceid = 'Unknown Stratum ' . $binary['stratum'] . ' Service';
323
324        /*
325         * Reference Clock Identifier
326         *
327         * Identifies the particular reference clock.
328         */
329        $refid = strtoupper($binary['referenceid']);
330        switch($binary['stratum']) {
331            case 0:
332                if (substr($refid, 0, 3) === 'DCN') {
333                    $ntpserviceid = 'DCN routing protocol';
334                } else if (substr($refid, 0, 4) === 'NIST') {
335                    $ntpserviceid = 'NIST public modem';
336                } else if (substr($refid, 0, 3) === 'TSP') {
337                    $ntpserviceid = 'TSP time protocol';
338                } else if (substr($refid, 0, 3) === 'DTS') {
339                    $ntpserviceid = 'Digital Time Service';
340                }
341                break;
342
343            case 1:
344                if (substr($refid, 0, 4) === 'ATOM') {
345                    $ntpserviceid = 'Atomic Clock (calibrated)';
346                } else if (substr($refid, 0, 3) === 'VLF') {
347                    $ntpserviceid = 'VLF radio';
348                } else if ($refid === 'CALLSIGN') {
349                    $ntpserviceid = 'Generic radio';
350                } else if (substr($refid, 0, 4) === 'LORC') {
351                    $ntpserviceid = 'LORAN-C radionavigation';
352                } else if (substr($refid, 0, 4) === 'GOES') {
353                    $ntpserviceid = 'GOES UHF environment satellite';
354                } else if (substr($refid, 0, 3) === 'GPS') {
355                    $ntpserviceid = 'GPS UHF satellite positioning';
356                }
357                break;
358
359            default:
360                $ntpserviceid  = ord(substr($binary['referenceid'], 0, 1));
361                $ntpserviceid .= '.';
362                $ntpserviceid .= ord(substr($binary['referenceid'], 1, 1));
363                $ntpserviceid .= '.';
364                $ntpserviceid .= ord(substr($binary['referenceid'], 2, 1));
365                $ntpserviceid .= '.';
366                $ntpserviceid .= ord(substr($binary['referenceid'], 3, 1));
367                break;
368        }
369
370        $this->_info['ntpid'] = $ntpserviceid;
371
372        /*
373         * Stratum
374         *
375         * Indicates the stratum level of the local clock
376         */
377        switch($binary['stratum']) {
378            case 0:
379                $this->_info['stratum'] = 'undefined';
380                break;
381
382            case 1:
383                $this->_info['stratum'] = 'primary reference';
384                break;
385
386            default:
387                $this->_info['stratum'] = 'secondary reference';
388                break;
389        }
390
391        /*
392         * Indicates the total roundtrip delay to the primary reference source at the
393         * root of the synchronization subnet, in seconds.
394         *
395         * Both positive and negative values, depending on clock precision and skew, are
396         * possible.
397         */
398        $this->_info['rootdelay'] = $binary['rootdelay'];
399
400        /*
401         * Indicates the maximum error relative to the primary reference source at the
402         * root of the synchronization subnet, in seconds.
403         *
404         * Only positive values greater than zero are possible.
405         */
406        $this->_info['rootdispersion'] = $binary['rootdispersion'];
407
408        /*
409         * The roundtrip delay of the peer clock relative to the local clock
410         * over the network path between them, in seconds.
411         *
412         * Note that this variable can take on both positive and negative values,
413         * depending on clock precision and skew-error accumulation.
414         */
415        $this->_info['roundtrip']  = $binary['receivestamp'];
416        $this->_info['roundtrip'] -= $binary['originatestamp'];
417        $this->_info['roundtrip'] -= $binary['transmitstamp'];
418        $this->_info['roundtrip'] += $binary['clientreceived'];
419        $this->_info['roundtrip'] /= 2;
420
421        // The offset of the peer clock relative to the local clock, in seconds.
422        $this->_info['offset']  = $binary['receivestamp'];
423        $this->_info['offset'] -= $binary['originatestamp'];
424        $this->_info['offset'] += $binary['transmitstamp'];
425        $this->_info['offset'] -= $binary['clientreceived'];
426        $this->_info['offset'] /= 2;
427        $time = (time() - $this->_info['offset']);
428
429        return $time;
430    }
431}