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