View Javadoc
1   package org.apache.commons.net.ntp;
2   /*
3    * Licensed to the Apache Software Foundation (ASF) under one or more
4    * contributor license agreements.  See the NOTICE file distributed with
5    * this work for additional information regarding copyright ownership.
6    * The ASF licenses this file to You under the Apache License, Version 2.0
7    * (the "License"); you may not use this file except in compliance with
8    * the License.  You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.net.DatagramPacket;
20  
21  /***
22   * Implementation of NtpV3Packet with methods converting Java objects to/from
23   * the Network Time Protocol (NTP) data message header format described in RFC-1305.
24   *
25   * @version $Revision: 1741829 $
26   */
27  public class NtpV3Impl implements NtpV3Packet
28  {
29  
30      private static final int MODE_INDEX = 0;
31      private static final int MODE_SHIFT = 0;
32  
33      private static final int VERSION_INDEX = 0;
34      private static final int VERSION_SHIFT = 3;
35  
36      private static final int LI_INDEX = 0;
37      private static final int LI_SHIFT = 6;
38  
39      private static final int STRATUM_INDEX = 1;
40      private static final int POLL_INDEX = 2;
41      private static final int PRECISION_INDEX = 3;
42  
43      private static final int ROOT_DELAY_INDEX = 4;
44      private static final int ROOT_DISPERSION_INDEX = 8;
45      private static final int REFERENCE_ID_INDEX = 12;
46  
47      private static final int REFERENCE_TIMESTAMP_INDEX = 16;
48      private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
49      private static final int RECEIVE_TIMESTAMP_INDEX = 32;
50      private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
51  
52  //    private static final int KEY_IDENTIFIER_INDEX = 48;
53  //    private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
54  
55      private final byte[] buf = new byte[48];
56  
57      private volatile DatagramPacket dp;
58  
59      /** Creates a new instance of NtpV3Impl */
60      public NtpV3Impl()
61      {
62      }
63  
64      /***
65       * Returns mode as defined in RFC-1305 which is a 3-bit integer
66       * whose value is indicated by the MODE_xxx parameters.
67       *
68       * @return mode as defined in RFC-1305.
69       */
70      @Override
71      public int getMode()
72      {
73          return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
74      }
75  
76      /***
77       * Return human-readable name of message mode type as described in
78       * RFC 1305.
79       * @return mode name as string.
80       */
81      @Override
82      public String getModeName()
83      {
84          return NtpUtils.getModeName(getMode());
85      }
86  
87      /***
88       * Set mode as defined in RFC-1305.
89       *
90       * @param mode the mode to set
91       */
92      @Override
93      public void setMode(int mode)
94      {
95          buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
96      }
97  
98      /***
99       * Returns leap indicator as defined in RFC-1305 which is a two-bit code:
100      *  0=no warning
101      *  1=last minute has 61 seconds
102      *  2=last minute has 59 seconds
103      *  3=alarm condition (clock not synchronized)
104      *
105      * @return leap indicator as defined in RFC-1305.
106      */
107     @Override
108     public int getLeapIndicator()
109     {
110         return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3;
111     }
112 
113     /***
114      * Set leap indicator as defined in RFC-1305.
115      *
116      * @param li leap indicator.
117      */
118     @Override
119     public void setLeapIndicator(int li)
120     {
121         buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT));
122     }
123 
124     /***
125      * Returns poll interval as defined in RFC-1305, which is an eight-bit
126      * signed integer indicating the maximum interval between successive
127      * messages, in seconds to the nearest power of two (e.g. value of six
128      * indicates an interval of 64 seconds. The values that can appear in
129      * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive.
130      *
131      * @return poll interval as defined in RFC-1305.
132      */
133     @Override
134     public int getPoll()
135     {
136         return buf[POLL_INDEX];
137     }
138 
139     /***
140      * Set poll interval as defined in RFC-1305.
141      *
142      * @param poll poll interval.
143      */
144     @Override
145     public void setPoll(int poll)
146     {
147         buf[POLL_INDEX] = (byte) (poll & 0xFF);
148     }
149 
150     /***
151      * Returns precision as defined in RFC-1305 encoded as an 8-bit signed
152      * integer (seconds to nearest power of two).
153      * Values normally range from -6 to -20.
154      *
155      * @return precision as defined in RFC-1305.
156      */
157     @Override
158     public int getPrecision()
159     {
160         return buf[PRECISION_INDEX];
161     }
162 
163     /***
164      * Set precision as defined in RFC-1305.
165      * @param precision the precision to set
166      * @since 3.4
167      */
168     @Override
169     public void setPrecision(int precision)
170     {
171         buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
172     }
173 
174     /***
175      * Returns NTP version number as defined in RFC-1305.
176      *
177      * @return NTP version number.
178      */
179     @Override
180     public int getVersion()
181     {
182         return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7;
183     }
184 
185     /***
186      * Set NTP version as defined in RFC-1305.
187      *
188      * @param version NTP version.
189      */
190     @Override
191     public void setVersion(int version)
192     {
193         buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT));
194     }
195 
196     /***
197      * Returns Stratum as defined in RFC-1305, which indicates the stratum level
198      * of the local clock, with values defined as follows: 0=unspecified,
199      * 1=primary ref clock, and all others a secondary reference (via NTP).
200      *
201      * @return Stratum level as defined in RFC-1305.
202      */
203     @Override
204     public int getStratum()
205     {
206         return ui(buf[STRATUM_INDEX]);
207     }
208 
209     /***
210      * Set stratum level as defined in RFC-1305.
211      *
212      * @param stratum stratum level.
213      */
214     @Override
215     public void setStratum(int stratum)
216     {
217         buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
218     }
219 
220     /***
221      * Return root delay as defined in RFC-1305, which is the total roundtrip delay
222      * to the primary reference source, in seconds. Values can take positive and
223      * negative values, depending on clock precision and skew.
224      *
225      * @return root delay as defined in RFC-1305.
226      */
227     @Override
228     public int getRootDelay()
229     {
230         return getInt(ROOT_DELAY_INDEX);
231     }
232 
233     /***
234      * Set root delay as defined in RFC-1305.
235      *
236      * @param delay root delay
237      * @since 3.4
238      */
239     @Override
240     public void setRootDelay(int delay)
241     {
242         setInt(ROOT_DELAY_INDEX, delay);
243     }
244 
245     /**
246      * Return root delay as defined in RFC-1305 in milliseconds, which is
247      * the total roundtrip delay to the primary reference source, in
248      * seconds. Values can take positive and negative values, depending
249      * on clock precision and skew.
250      *
251      * @return root delay in milliseconds
252      */
253     @Override
254     public double getRootDelayInMillisDouble()
255     {
256         double l = getRootDelay();
257         return l / 65.536;
258     }
259 
260     /***
261      * Returns root dispersion as defined in RFC-1305.
262      * @return root dispersion.
263      */
264     @Override
265     public int getRootDispersion()
266     {
267         return getInt(ROOT_DISPERSION_INDEX);
268     }
269 
270     /***
271      * Set root dispersion as defined in RFC-1305.
272      *
273      * @param dispersion root dispersion
274      * @since 3.4
275      */
276     @Override
277     public void setRootDispersion(int dispersion)
278     {
279         setInt(ROOT_DISPERSION_INDEX, dispersion);
280     }
281 
282     /***
283      * Returns root dispersion (as defined in RFC-1305) in milliseconds.
284      *
285      * @return root dispersion in milliseconds
286      */
287     @Override
288     public long getRootDispersionInMillis()
289     {
290         long l = getRootDispersion();
291         return (l * 1000) / 65536L;
292     }
293 
294     /***
295      * Returns root dispersion (as defined in RFC-1305) in milliseconds
296      * as double precision value.
297      *
298      * @return root dispersion in milliseconds
299      */
300     @Override
301     public double getRootDispersionInMillisDouble()
302     {
303         double l = getRootDispersion();
304         return l / 65.536;
305     }
306 
307     /***
308      * Set reference clock identifier field with 32-bit unsigned integer value.
309      * See RFC-1305 for description.
310      *
311      * @param refId reference clock identifier.
312      */
313     @Override
314     public void setReferenceId(int refId)
315     {
316         setInt(REFERENCE_ID_INDEX, refId);
317     }
318 
319     /***
320      * Returns the reference id as defined in RFC-1305, which is
321      * a 32-bit integer whose value is dependent on several criteria.
322      *
323      * @return the reference id as defined in RFC-1305.
324      */
325     @Override
326     public int getReferenceId()
327     {
328         return getInt(REFERENCE_ID_INDEX);
329     }
330 
331     /***
332      * Returns the reference id string. String cannot be null but
333      * value is dependent on the version of the NTP spec supported
334      * and stratum level. Value can be an empty string, clock type string,
335      * IP address, or a hex string.
336      *
337      * @return the reference id string.
338      */
339     @Override
340     public String getReferenceIdString()
341     {
342         int version = getVersion();
343         int stratum = getStratum();
344         if (version == VERSION_3 || version == VERSION_4) {
345             if (stratum == 0 || stratum == 1) {
346                 return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
347             }
348             // in NTPv4 servers this is latest transmit timestamp of ref source
349             if (version == VERSION_4) {
350                 return idAsHex();
351             }
352         }
353 
354         // Stratum 2 and higher this is a four-octet IPv4 address
355         // of the primary reference host.
356         if (stratum >= 2) {
357             return idAsIPAddress();
358         }
359         return idAsHex();
360     }
361 
362     /***
363      * Returns Reference id as dotted IP address.
364      * @return refId as IP address string.
365      */
366     private String idAsIPAddress()
367     {
368         return ui(buf[REFERENCE_ID_INDEX]) + "." +
369                 ui(buf[REFERENCE_ID_INDEX + 1]) + "." +
370                 ui(buf[REFERENCE_ID_INDEX + 2]) + "." +
371                 ui(buf[REFERENCE_ID_INDEX + 3]);
372     }
373 
374     private String idAsString()
375     {
376         StringBuilder id = new StringBuilder();
377         for (int i = 0; i <= 3; i++) {
378             char c = (char) buf[REFERENCE_ID_INDEX + i];
379             if (c == 0) {  // 0-terminated string
380                 break;
381             }
382             id.append(c);
383         }
384         return id.toString();
385     }
386 
387     private String idAsHex()
388     {
389         return Integer.toHexString(getReferenceId());
390     }
391 
392     /***
393      * Returns the transmit timestamp as defined in RFC-1305.
394      *
395      * @return the transmit timestamp as defined in RFC-1305.
396      * Never returns a null object.
397      */
398     @Override
399     public TimeStamp getTransmitTimeStamp()
400     {
401         return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
402     }
403 
404     /***
405      * Set transmit time with NTP timestamp.
406      * If <code>ts</code> is null then zero time is used.
407      *
408      * @param ts NTP timestamp
409      */
410     @Override
411     public void setTransmitTime(TimeStamp ts)
412     {
413         setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
414     }
415 
416     /***
417      * Set originate timestamp given NTP TimeStamp object.
418      * If <code>ts</code> is null then zero time is used.
419      *
420      * @param ts NTP timestamp
421      */
422     @Override
423     public void setOriginateTimeStamp(TimeStamp ts)
424     {
425         setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
426     }
427 
428     /***
429      * Returns the originate time as defined in RFC-1305.
430      *
431      * @return the originate time.
432      * Never returns null.
433      */
434     @Override
435     public TimeStamp getOriginateTimeStamp()
436     {
437         return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
438     }
439 
440     /***
441      * Returns the reference time as defined in RFC-1305.
442      *
443      * @return the reference time as <code>TimeStamp</code> object.
444      * Never returns null.
445      */
446     @Override
447     public TimeStamp getReferenceTimeStamp()
448     {
449         return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
450     }
451 
452     /***
453      * Set Reference time with NTP timestamp. If <code>ts</code> is null
454      * then zero time is used.
455      *
456      * @param ts NTP timestamp
457      */
458     @Override
459     public void setReferenceTime(TimeStamp ts)
460     {
461         setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
462     }
463 
464     /***
465      * Returns receive timestamp as defined in RFC-1305.
466      *
467      * @return the receive time.
468      * Never returns null.
469      */
470     @Override
471     public TimeStamp getReceiveTimeStamp()
472     {
473         return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
474     }
475 
476     /***
477      * Set receive timestamp given NTP TimeStamp object.
478      * If <code>ts</code> is null then zero time is used.
479      *
480      * @param ts timestamp
481      */
482     @Override
483     public void setReceiveTimeStamp(TimeStamp ts)
484     {
485         setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
486     }
487 
488     /***
489      * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
490      * correspond to the protocol used to obtain the timing information.
491      *
492      * @return packet type string identifier which in this case is "NTP".
493      */
494     @Override
495     public String getType()
496     {
497         return "NTP";
498     }
499 
500     /***
501      * @return 4 bytes as 32-bit int
502      */
503     private int getInt(int index)
504     {
505         int i = ui(buf[index]) << 24 |
506                 ui(buf[index + 1]) << 16 |
507                 ui(buf[index + 2]) << 8 |
508                 ui(buf[index + 3]);
509 
510         return i;
511     }
512 
513     /***
514      * Set integer value at index position.
515      *
516      * @param idx index position
517      * @param value 32-bit int value
518      */
519     private void setInt(int idx, int value)
520     {
521         for (int i=3; i >= 0; i--) {
522             buf[idx + i] = (byte) (value & 0xff);
523             value >>>= 8; // shift right one-byte
524         }
525     }
526 
527     /**
528      * Get NTP Timestamp at specified starting index.
529      *
530      * @param index index into data array
531      * @return TimeStamp object for 64 bits starting at index
532      */
533     private TimeStamp getTimestamp(int index)
534     {
535         return new TimeStamp(getLong(index));
536     }
537 
538     /***
539      * Get Long value represented by bits starting at specified index.
540      *
541      * @return 8 bytes as 64-bit long
542      */
543     private long getLong(int index)
544     {
545         long i = ul(buf[index]) << 56 |
546                 ul(buf[index + 1]) << 48 |
547                 ul(buf[index + 2]) << 40 |
548                 ul(buf[index + 3]) << 32 |
549                 ul(buf[index + 4]) << 24 |
550                 ul(buf[index + 5]) << 16 |
551                 ul(buf[index + 6]) << 8 |
552                 ul(buf[index + 7]);
553         return i;
554     }
555 
556     /***
557      * Sets the NTP timestamp at the given array index.
558      *
559      * @param index index into the byte array.
560      * @param t TimeStamp.
561      */
562     private void setTimestamp(int index, TimeStamp t)
563     {
564         long ntpTime = (t == null) ? 0 : t.ntpValue();
565         // copy 64-bits from Long value into 8 x 8-bit bytes of array
566         // one byte at a time shifting 8-bits for each position.
567         for (int i = 7; i >= 0; i--) {
568             buf[index + i] = (byte) (ntpTime & 0xFF);
569             ntpTime >>>= 8; // shift to next byte
570         }
571         // buf[index] |= 0x80;  // only set if 1900 baseline....
572     }
573 
574     /***
575      * Returns the datagram packet with the NTP details already filled in.
576      *
577      * @return a datagram packet.
578      */
579     @Override
580     public synchronized DatagramPacket getDatagramPacket()
581     {
582         if (dp == null) {
583             dp = new DatagramPacket(buf, buf.length);
584             dp.setPort(NTP_PORT);
585         }
586         return dp;
587     }
588 
589     /***
590      * Set the contents of this object from source datagram packet.
591      *
592      * @param srcDp source DatagramPacket to copy contents from, never null.
593      * @throws IllegalArgumentException if srcDp is null or byte length is less than minimum length of 48 bytes
594      */
595     @Override
596     public void setDatagramPacket(DatagramPacket srcDp)
597     {
598         if (srcDp == null || srcDp.getLength() < buf.length) {
599             throw new IllegalArgumentException();
600         }
601         byte[] incomingBuf = srcDp.getData();
602         int len = srcDp.getLength();
603         if (len > buf.length) {
604             len = buf.length;
605         }
606         System.arraycopy(incomingBuf, 0, buf, 0, len);
607         DatagramPacket dp = getDatagramPacket();
608         dp.setAddress(srcDp.getAddress());
609         int port = srcDp.getPort();
610         dp.setPort(port > 0 ? port : NTP_PORT);
611         dp.setData(buf);
612     }
613 
614     /***
615      * Compares this object against the specified object.
616      * The result is <code>true</code> if and only if the argument is
617      * not <code>null</code> and is a <code>NtpV3Impl</code> object that
618      * contains the same values as this object.
619      *
620      * @param   obj   the object to compare with.
621      * @return  <code>true</code> if the objects are the same;
622      *          <code>false</code> otherwise.
623      * @since 3.4
624      */
625     @Override
626     public boolean equals(Object obj)
627     {
628         if (this == obj) {
629             return true;
630         }
631         if (obj == null || getClass() != obj.getClass()) {
632             return false;
633         }
634         NtpV3Impl other = (NtpV3Impl) obj;
635         return java.util.Arrays.equals(buf, other.buf);
636     }
637 
638     /***
639      * Computes a hashcode for this object. The result is the exclusive
640      * OR of the values of this object stored as a byte array.
641      *
642      * @return  a hash code value for this object.
643      * @since 3.4
644      */
645     @Override
646     public int hashCode()
647     {
648         return java.util.Arrays.hashCode(buf);
649     }
650 
651     /***
652      * Convert byte to unsigned integer.
653      * Java only has signed types so we have to do
654      * more work to get unsigned ops.
655      *
656      * @param b input byte
657      * @return unsigned int value of byte
658      */
659     protected static final int ui(byte b)
660     {
661         int i = b & 0xFF;
662         return i;
663     }
664 
665     /***
666      * Convert byte to unsigned long.
667      * Java only has signed types so we have to do
668      * more work to get unsigned ops
669      *
670      * @param b input byte
671      * @return unsigned long value of byte
672      */
673     protected static final long ul(byte b)
674     {
675         long i = b & 0xFF;
676         return i;
677     }
678 
679     /***
680      * Returns details of NTP packet as a string.
681      *
682      * @return details of NTP packet as a string.
683      */
684     @Override
685     public String toString()
686     {
687         return "[" +
688                 "version:" + getVersion() +
689                 ", mode:" + getMode() +
690                 ", poll:" + getPoll() +
691                 ", precision:" + getPrecision() +
692                 ", delay:" + getRootDelay() +
693                 ", dispersion(ms):" + getRootDispersionInMillisDouble() +
694                 ", id:" + getReferenceIdString() +
695                 ", xmitTime:" + getTransmitTimeStamp().toDateString() +
696                 " ]";
697     }
698 
699 }