001    package org.apache.commons.net.ntp;
002    /*
003     * Copyright 2001-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    import java.net.DatagramPacket;
018    
019    /***
020     * Implementation of NtpV3Packet with methods converting Java objects to/from
021     * the Network Time Protocol (NTP) data message header format described in RFC-1305.
022     *
023     * @author Naz Irizarry, MITRE Corp
024     * @author Jason Mathews, MITRE Corp
025     *
026     * @version $Revision: 165675 $ $Date: 2005-05-02 21:09:55 +0100 (Mon, 02 May 2005) $
027     */
028    public class NtpV3Impl implements NtpV3Packet
029    {
030    
031        private static final int MODE_INDEX = 0;
032        private static final int MODE_SHIFT = 0;
033    
034        private static final int VERSION_INDEX = 0;
035        private static final int VERSION_SHIFT = 3;
036    
037        private static final int LI_INDEX = 0;
038        private static final int LI_SHIFT = 6;
039    
040        private static final int STRATUM_INDEX = 1;
041        private static final int POLL_INDEX = 2;
042        private static final int PRECISION_INDEX = 3;
043    
044        private static final int ROOT_DELAY_INDEX = 4;
045        private static final int ROOT_DISPERSION_INDEX = 8;
046        private static final int REFERENCE_ID_INDEX = 12;
047    
048        private static final int REFERENCE_TIMESTAMP_INDEX = 16;
049        private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
050        private static final int RECEIVE_TIMESTAMP_INDEX = 32;
051        private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
052    
053        private static final int KEY_IDENTIFIER_INDEX = 48;
054        private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
055    
056        private byte[] buf = new byte[48];
057    
058        private DatagramPacket dp;
059    
060        /** Creates a new instance of NtpV3Impl */
061        public NtpV3Impl()
062        {
063        }
064    
065        /***
066         * Returns mode as defined in RFC-1305 which is a 3-bit integer
067         * whose value is indicated by the MODE_xxx parameters.
068         *
069         * @return mode as defined in RFC-1305.
070         */
071        public int getMode()
072        {
073            return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
074        }
075    
076        /***
077         * Return human-readable name of message mode type as described in
078         * RFC 1305.
079         * @return mode name as string.
080         */
081        public String getModeName()
082        {
083            return NtpUtils.getModeName(getMode());
084        }
085    
086        /***
087         * Set mode as defined in RFC-1305.
088         * @param mode
089         */
090        public void setMode(int mode)
091        {
092            buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
093        }
094    
095        /***
096         * Returns leap indicator as defined in RFC-1305 which is a two-bit code:
097         *  0=no warning
098         *  1=last minute has 61 seconds
099         *  2=last minute has 59 seconds
100         *  3=alarm condition (clock not synchronized)
101         *
102         * @return leap indicator as defined in RFC-1305.
103         */
104        public int getLeapIndicator()
105        {
106            return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3;
107        }
108    
109        /***
110         * Set leap indicator as defined in RFC-1305.
111         * @param li leap indicator.
112         */
113        public void setLeapIndicator(int li)
114        {
115            buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT));
116        }
117    
118        /***
119         * Returns poll interval as defined in RFC-1305, which is an eight-bit
120         * signed integer indicating the maximum interval between successive
121         * messages, in seconds to the nearest power of two (e.g. value of six
122         * indicates an interval of 64 seconds. The values that can appear in
123         * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive.
124         *
125         * @return poll interval as defined in RFC-1305.
126         */
127        public int getPoll()
128        {
129            return (int) (buf[POLL_INDEX]);
130        }
131    
132        /***
133         * Set poll interval as defined in RFC-1305.
134         *
135         * @param poll poll interval.
136         */
137        public void setPoll(int poll)
138        {
139            buf[POLL_INDEX] = (byte) (poll & 0xFF);
140        }
141    
142        /***
143         * Returns precision as defined in RFC-1305 encoded as an 8-bit signed
144         * integer (seconds to nearest power of two).
145         * Values normally range from -6 to -20.
146         *
147         * @return precision as defined in RFC-1305.
148         */
149        public int getPrecision()
150        {
151            return (int) buf[PRECISION_INDEX];
152        }
153    
154        /***
155         * Set precision as defined in RFC-1305.
156         * @param precision
157         */
158        public void setPrecision(int precision)
159        {
160            buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
161        }
162    
163        /***
164         * Returns NTP version number as defined in RFC-1305.
165         *
166         * @return NTP version number.
167         */
168        public int getVersion()
169        {
170            return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7;
171        }
172    
173        /***
174         * Set NTP version as defined in RFC-1305.
175         *
176         * @param version NTP version.
177         */
178        public void setVersion(int version)
179        {
180            buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT));
181        }
182    
183        /***
184         * Returns Stratum as defined in RFC-1305, which indicates the stratum level
185         * of the local clock, with values defined as follows: 0=unspecified,
186         * 1=primary ref clock, and all others a secondary reference (via NTP).
187         *
188         * @return Stratum level as defined in RFC-1305.
189         */
190        public int getStratum()
191        {
192            return ui(buf[STRATUM_INDEX]);
193        }
194    
195        /***
196         * Set stratum level as defined in RFC-1305.
197         *
198         * @param stratum stratum level.
199         */
200        public void setStratum(int stratum)
201        {
202            buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
203        }
204    
205        /***
206         * Return root delay as defined in RFC-1305, which is the total roundtrip delay
207         * to the primary reference source, in seconds. Values can take positive and
208         * negative values, depending on clock precision and skew.
209         *
210         * @return root delay as defined in RFC-1305.
211         */
212        public int getRootDelay()
213        {
214            return getInt(ROOT_DELAY_INDEX);
215        }
216    
217        /***
218         * Return root delay as defined in RFC-1305 in milliseconds, which is
219         * the total roundtrip delay to the primary reference source, in
220         * seconds. Values can take positive and negative values, depending
221         * on clock precision and skew.
222         *
223         * @return root delay in milliseconds
224         */
225        public double getRootDelayInMillisDouble()
226        {
227            double l = getRootDelay();
228            return l / 65.536;
229        }
230    
231        /***
232         * Returns root dispersion as defined in RFC-1305.
233         * @return root dispersion.
234         */
235        public int getRootDispersion()
236        {
237            return getInt(ROOT_DISPERSION_INDEX);
238        }
239    
240        /***
241         * Returns root dispersion (as defined in RFC-1305) in milliseconds.
242         *
243         * @return root dispersion in milliseconds
244         */
245        public long getRootDispersionInMillis()
246        {
247            long l = getRootDispersion();
248            return (l * 1000) / 65536L;
249        }
250    
251        /***
252         * Returns root dispersion (as defined in RFC-1305) in milliseconds
253         * as double precision value.
254         *
255         * @return root dispersion in milliseconds
256         */
257        public double getRootDispersionInMillisDouble()
258        {
259            double l = getRootDispersion();
260            return l / 65.536;
261        }
262    
263        /***
264         * Set reference clock identifier field with 32-bit unsigned integer value.
265         * See RFC-1305 for description.
266         *
267         * @param refId reference clock identifier.
268         */
269        public void setReferenceId(int refId)
270        {
271            for (int i = 3; i >= 0; i--) {
272                buf[REFERENCE_ID_INDEX + i] = (byte) (refId & 0xff);
273                refId >>>= 8; // shift right one-byte
274            }
275        }
276    
277        /***
278         * Returns the reference id as defined in RFC-1305, which is
279         * a 32-bit integer whose value is dependent on several criteria.
280         *
281         * @return the reference id as defined in RFC-1305.
282         */
283        public int getReferenceId()
284        {
285            return getInt(REFERENCE_ID_INDEX);
286        }
287    
288        /***
289         * Returns the reference id string. String cannot be null but
290         * value is dependent on the version of the NTP spec supported
291         * and stratum level. Value can be an empty string, clock type string,
292         * IP address, or a hex string.
293         *
294         * @return the reference id string.
295         */
296        public String getReferenceIdString()
297        {
298            int version = getVersion();
299            int stratum = getStratum();
300            if (version == VERSION_3 || version == VERSION_4) {
301                if (stratum == 0 || stratum == 1) {
302                    return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
303                }
304                // in NTPv4 servers this is latest transmit timestamp of ref source
305                if (version == VERSION_4)
306                    return idAsHex();
307            }
308    
309            // Stratum 2 and higher this is a four-octet IPv4 address
310            // of the primary reference host.
311            if (stratum >= 2) {
312                return idAsIPAddress();
313            }
314            return idAsHex();
315        }
316    
317        /***
318         * Returns Reference id as dotted IP address.
319         * @return refId as IP address string.
320         */
321        private String idAsIPAddress()
322        {
323            return ui(buf[REFERENCE_ID_INDEX]) + "." +
324                    ui(buf[REFERENCE_ID_INDEX + 1]) + "." +
325                    ui(buf[REFERENCE_ID_INDEX + 2]) + "." +
326                    ui(buf[REFERENCE_ID_INDEX + 3]);
327        }
328    
329        private String idAsString()
330        {
331            String id = "";
332            for (int i = 0; i <= 3; i++) {
333                char c = (char) buf[REFERENCE_ID_INDEX + i];
334                if (c == 0) break; // 0-terminated string
335                id = id + c;
336            }
337            return id;
338        }
339    
340        private String idAsHex()
341        {
342            return Integer.toHexString(getReferenceId());
343        }
344    
345        /***
346         * Returns the transmit timestamp as defined in RFC-1305.
347         *
348         * @return the transmit timestamp as defined in RFC-1305.
349         * Never returns a null object.
350         */
351        public TimeStamp getTransmitTimeStamp()
352        {
353            return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
354        }
355    
356        /***
357         * Set transmit time with NTP timestamp.
358         * If <code>ts</code> is null then zero time is used.
359         *
360         * @param ts NTP timestamp
361         */
362        public void setTransmitTime(TimeStamp ts)
363        {
364            setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
365        }
366    
367        /***
368         * Set originate timestamp given NTP TimeStamp object.
369         * If <code>ts</code> is null then zero time is used.
370         *
371         * @param ts NTP timestamp
372         */
373        public void setOriginateTimeStamp(TimeStamp ts)
374        {
375            setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
376        }
377    
378        /***
379         * Returns the originate time as defined in RFC-1305.
380         *
381         * @return the originate time.
382         * Never returns null.
383         */
384        public TimeStamp getOriginateTimeStamp()
385        {
386            return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
387        }
388    
389        /***
390         * Returns the reference time as defined in RFC-1305.
391         *
392         * @return the reference time as <code>TimeStamp</code> object.
393         * Never returns null.
394         */
395        public TimeStamp getReferenceTimeStamp()
396        {
397            return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
398        }
399    
400        /***
401         * Set Reference time with NTP timestamp. If <code>ts</code> is null
402         * then zero time is used.
403         *
404         * @param ts NTP timestamp
405         */
406        public void setReferenceTime(TimeStamp ts)
407        {
408            setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
409        }
410    
411        /***
412         * Returns receive timestamp as defined in RFC-1305.
413         *
414         * @return the receive time.
415         * Never returns null.
416         */
417        public TimeStamp getReceiveTimeStamp()
418        {
419            return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
420        }
421    
422        /***
423         * Set receive timestamp given NTP TimeStamp object.
424         * If <code>ts</code> is null then zero time is used.
425         *
426         * @param ts timestamp
427         */
428        public void setReceiveTimeStamp(TimeStamp ts)
429        {
430            setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
431        }
432    
433        /***
434         * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
435         * correspond to the protocol used to obtain the timing information.
436         *
437         * @return packet type string identifier which in this case is "NTP".
438         */
439        public String getType()
440        {
441            return "NTP";
442        }
443    
444        /***
445         * @return 4 bytes as 32-bit int
446         */
447        private int getInt(int index)
448        {
449            int i = ui(buf[index]) << 24 |
450                    ui(buf[index + 1]) << 16 |
451                    ui(buf[index + 2]) << 8 |
452                    ui(buf[index + 3]);
453    
454            return i;
455        }
456    
457        /***
458         * Get NTP Timestamp at specified starting index.
459         *
460         * @param index index into data array
461         * @return TimeStamp object for 64 bits starting at index
462         */
463        private TimeStamp getTimestamp(int index)
464        {
465            return new TimeStamp(getLong(index));
466        }
467    
468        /***
469         * Get Long value represented by bits starting at specified index.
470         *
471         * @return 8 bytes as 64-bit long
472         */
473        private long getLong(int index)
474        {
475            long i = ul(buf[index]) << 56 |
476                    ul(buf[index + 1]) << 48 |
477                    ul(buf[index + 2]) << 40 |
478                    ul(buf[index + 3]) << 32 |
479                    ul(buf[index + 4]) << 24 |
480                    ul(buf[index + 5]) << 16 |
481                    ul(buf[index + 6]) << 8 |
482                    ul(buf[index + 7]);
483            return i;
484        }
485    
486        /***
487         * Sets the NTP timestamp at the given array index.
488         *
489         * @param index index into the byte array.
490         * @param t TimeStamp.
491         */
492        private void setTimestamp(int index, TimeStamp t)
493        {
494            long ntpTime = (t == null) ? 0 : t.ntpValue();
495            // copy 64-bits from Long value into 8 x 8-bit bytes of array
496            // one byte at a time shifting 8-bits for each position.
497            for (int i = 7; i >= 0; i--) {
498                buf[index + i] = (byte) (ntpTime & 0xFF);
499                ntpTime >>>= 8; // shift to next byte
500            }
501            // buf[index] |= 0x80;  // only set if 1900 baseline....
502        }
503    
504        /***
505         * Returns the datagram packet with the NTP details already filled in.
506         *
507         * @return a datagram packet.
508         */
509        public DatagramPacket getDatagramPacket()
510        {
511            if (dp == null)
512                synchronized(this) {
513                    if (dp == null) {
514                        dp = new DatagramPacket(buf, buf.length);
515                        dp.setPort(NTP_PORT);
516                    }
517                }
518            return dp;
519        }
520    
521        /***
522         * Set the contents of this object from source datagram packet.
523         *
524         * @param srcDp source DatagramPacket to copy contents from.
525         */
526        public void setDatagramPacket(DatagramPacket srcDp)
527        {
528            byte[] incomingBuf = srcDp.getData();
529            int len = srcDp.getLength();
530            if (len > buf.length)
531                len = buf.length;
532    
533            System.arraycopy(incomingBuf, 0, buf, 0, len);
534        }
535    
536        /***
537         * Convert byte to unsigned integer.
538         * Java only has signed types so we have to do
539         * more work to get unsigned ops.
540         *
541         * @param b
542         * @return unsigned int value of byte
543         */
544        protected final static int ui(byte b)
545        {
546            int i = b & 0xFF;
547            return i;
548        }
549    
550        /***
551         * Convert byte to unsigned long.
552         * Java only has signed types so we have to do
553         * more work to get unsigned ops
554         *
555         * @param b
556         * @return unsigned long value of byte
557         */
558        protected final static long ul(byte b)
559        {
560            long i = b & 0xFF;
561            return i;
562        }
563    
564        /***
565         * Returns details of NTP packet as a string.
566         *
567         * @return details of NTP packet as a string.
568         */
569        public String toString()
570        {
571            return "[" +
572                    "version:" + getVersion() +
573                    ", mode:" + getMode() +
574                    ", poll:" + getPoll() +
575                    ", precision:" + getPrecision() +
576                    ", delay:" + getRootDelay() +
577                    ", dispersion(ms):" + getRootDispersionInMillisDouble() +
578                    ", id:" + getReferenceIdString() +
579                    ", xmitTime:" + getTransmitTimeStamp().toDateString() +
580                    " ]";
581        }
582    
583    }