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: 1697280 $
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     public void setPrecision(int precision)
169     {
170         buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
171     }
172 
173     /***
174      * Returns NTP version number as defined in RFC-1305.
175      *
176      * @return NTP version number.
177      */
178 //    @Override
179     public int getVersion()
180     {
181         return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7;
182     }
183 
184     /***
185      * Set NTP version as defined in RFC-1305.
186      *
187      * @param version NTP version.
188      */
189 //    @Override
190     public void setVersion(int version)
191     {
192         buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT));
193     }
194 
195     /***
196      * Returns Stratum as defined in RFC-1305, which indicates the stratum level
197      * of the local clock, with values defined as follows: 0=unspecified,
198      * 1=primary ref clock, and all others a secondary reference (via NTP).
199      *
200      * @return Stratum level as defined in RFC-1305.
201      */
202 //    @Override
203     public int getStratum()
204     {
205         return ui(buf[STRATUM_INDEX]);
206     }
207 
208     /***
209      * Set stratum level as defined in RFC-1305.
210      *
211      * @param stratum stratum level.
212      */
213 //    @Override
214     public void setStratum(int stratum)
215     {
216         buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
217     }
218 
219     /***
220      * Return root delay as defined in RFC-1305, which is the total roundtrip delay
221      * to the primary reference source, in seconds. Values can take positive and
222      * negative values, depending on clock precision and skew.
223      *
224      * @return root delay as defined in RFC-1305.
225      */
226 //    @Override
227     public int getRootDelay()
228     {
229         return getInt(ROOT_DELAY_INDEX);
230     }
231 
232     /***
233      * Set root delay as defined in RFC-1305.
234      *
235      * @param delay root delay
236      * @since 3.4
237      */
238 //    @Override
239     public void setRootDelay(int delay)
240     {
241         setInt(ROOT_DELAY_INDEX, delay);
242     }
243 
244     /**
245      * Return root delay as defined in RFC-1305 in milliseconds, which is
246      * the total roundtrip delay to the primary reference source, in
247      * seconds. Values can take positive and negative values, depending
248      * on clock precision and skew.
249      *
250      * @return root delay in milliseconds
251      */
252 //    @Override
253     public double getRootDelayInMillisDouble()
254     {
255         double l = getRootDelay();
256         return l / 65.536;
257     }
258 
259     /***
260      * Returns root dispersion as defined in RFC-1305.
261      * @return root dispersion.
262      */
263 //    @Override
264     public int getRootDispersion()
265     {
266         return getInt(ROOT_DISPERSION_INDEX);
267     }
268 
269     /***
270      * Set root dispersion as defined in RFC-1305.
271      *
272      * @param dispersion root dispersion
273      * @since 3.4
274      */
275 //    @Override
276     public void setRootDispersion(int dispersion)
277     {
278         setInt(ROOT_DISPERSION_INDEX, dispersion);
279     }
280 
281     /***
282      * Returns root dispersion (as defined in RFC-1305) in milliseconds.
283      *
284      * @return root dispersion in milliseconds
285      */
286 //    @Override
287     public long getRootDispersionInMillis()
288     {
289         long l = getRootDispersion();
290         return (l * 1000) / 65536L;
291     }
292 
293     /***
294      * Returns root dispersion (as defined in RFC-1305) in milliseconds
295      * as double precision value.
296      *
297      * @return root dispersion in milliseconds
298      */
299 //    @Override
300     public double getRootDispersionInMillisDouble()
301     {
302         double l = getRootDispersion();
303         return l / 65.536;
304     }
305 
306     /***
307      * Set reference clock identifier field with 32-bit unsigned integer value.
308      * See RFC-1305 for description.
309      *
310      * @param refId reference clock identifier.
311      */
312 //    @Override
313     public void setReferenceId(int refId)
314     {
315         setInt(REFERENCE_ID_INDEX, refId);
316     }
317 
318     /***
319      * Returns the reference id as defined in RFC-1305, which is
320      * a 32-bit integer whose value is dependent on several criteria.
321      *
322      * @return the reference id as defined in RFC-1305.
323      */
324 //    @Override
325     public int getReferenceId()
326     {
327         return getInt(REFERENCE_ID_INDEX);
328     }
329 
330     /***
331      * Returns the reference id string. String cannot be null but
332      * value is dependent on the version of the NTP spec supported
333      * and stratum level. Value can be an empty string, clock type string,
334      * IP address, or a hex string.
335      *
336      * @return the reference id string.
337      */
338 //    @Override
339     public String getReferenceIdString()
340     {
341         int version = getVersion();
342         int stratum = getStratum();
343         if (version == VERSION_3 || version == VERSION_4) {
344             if (stratum == 0 || stratum == 1) {
345                 return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
346             }
347             // in NTPv4 servers this is latest transmit timestamp of ref source
348             if (version == VERSION_4) {
349                 return idAsHex();
350             }
351         }
352 
353         // Stratum 2 and higher this is a four-octet IPv4 address
354         // of the primary reference host.
355         if (stratum >= 2) {
356             return idAsIPAddress();
357         }
358         return idAsHex();
359     }
360 
361     /***
362      * Returns Reference id as dotted IP address.
363      * @return refId as IP address string.
364      */
365     private String idAsIPAddress()
366     {
367         return ui(buf[REFERENCE_ID_INDEX]) + "." +
368                 ui(buf[REFERENCE_ID_INDEX + 1]) + "." +
369                 ui(buf[REFERENCE_ID_INDEX + 2]) + "." +
370                 ui(buf[REFERENCE_ID_INDEX + 3]);
371     }
372 
373     private String idAsString()
374     {
375         StringBuilder id = new StringBuilder();
376         for (int i = 0; i <= 3; i++) {
377             char c = (char) buf[REFERENCE_ID_INDEX + i];
378             if (c == 0) {  // 0-terminated string
379                 break;
380             }
381             id.append(c);
382         }
383         return id.toString();
384     }
385 
386     private String idAsHex()
387     {
388         return Integer.toHexString(getReferenceId());
389     }
390 
391     /***
392      * Returns the transmit timestamp as defined in RFC-1305.
393      *
394      * @return the transmit timestamp as defined in RFC-1305.
395      * Never returns a null object.
396      */
397 //    @Override
398     public TimeStamp getTransmitTimeStamp()
399     {
400         return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
401     }
402 
403     /***
404      * Set transmit time with NTP timestamp.
405      * If <code>ts</code> is null then zero time is used.
406      *
407      * @param ts NTP timestamp
408      */
409 //    @Override
410     public void setTransmitTime(TimeStamp ts)
411     {
412         setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
413     }
414 
415     /***
416      * Set originate timestamp given NTP TimeStamp object.
417      * If <code>ts</code> is null then zero time is used.
418      *
419      * @param ts NTP timestamp
420      */
421 //    @Override
422     public void setOriginateTimeStamp(TimeStamp ts)
423     {
424         setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
425     }
426 
427     /***
428      * Returns the originate time as defined in RFC-1305.
429      *
430      * @return the originate time.
431      * Never returns null.
432      */
433 //    @Override
434     public TimeStamp getOriginateTimeStamp()
435     {
436         return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
437     }
438 
439     /***
440      * Returns the reference time as defined in RFC-1305.
441      *
442      * @return the reference time as <code>TimeStamp</code> object.
443      * Never returns null.
444      */
445 //    @Override
446     public TimeStamp getReferenceTimeStamp()
447     {
448         return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
449     }
450 
451     /***
452      * Set Reference time with NTP timestamp. If <code>ts</code> is null
453      * then zero time is used.
454      *
455      * @param ts NTP timestamp
456      */
457 //    @Override
458     public void setReferenceTime(TimeStamp ts)
459     {
460         setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
461     }
462 
463     /***
464      * Returns receive timestamp as defined in RFC-1305.
465      *
466      * @return the receive time.
467      * Never returns null.
468      */
469 //    @Override
470     public TimeStamp getReceiveTimeStamp()
471     {
472         return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
473     }
474 
475     /***
476      * Set receive timestamp given NTP TimeStamp object.
477      * If <code>ts</code> is null then zero time is used.
478      *
479      * @param ts timestamp
480      */
481 //    @Override
482     public void setReceiveTimeStamp(TimeStamp ts)
483     {
484         setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
485     }
486 
487     /***
488      * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
489      * correspond to the protocol used to obtain the timing information.
490      *
491      * @return packet type string identifier which in this case is "NTP".
492      */
493 //    @Override
494     public String getType()
495     {
496         return "NTP";
497     }
498 
499     /***
500      * @return 4 bytes as 32-bit int
501      */
502     private int getInt(int index)
503     {
504         int i = ui(buf[index]) << 24 |
505                 ui(buf[index + 1]) << 16 |
506                 ui(buf[index + 2]) << 8 |
507                 ui(buf[index + 3]);
508 
509         return i;
510     }
511 
512     /***
513      * Set integer value at index position.
514      *
515      * @param idx index position
516      * @param value 32-bit int value
517      */
518     private void setInt(int idx, int value)
519     {
520         for (int i=3; i >= 0; i--) {
521             buf[idx + i] = (byte) (value & 0xff);
522             value >>>= 8; // shift right one-byte
523         }
524     }
525 
526     /**
527      * Get NTP Timestamp at specified starting index.
528      *
529      * @param index index into data array
530      * @return TimeStamp object for 64 bits starting at index
531      */
532     private TimeStamp getTimestamp(int index)
533     {
534         return new TimeStamp(getLong(index));
535     }
536 
537     /***
538      * Get Long value represented by bits starting at specified index.
539      *
540      * @return 8 bytes as 64-bit long
541      */
542     private long getLong(int index)
543     {
544         long i = ul(buf[index]) << 56 |
545                 ul(buf[index + 1]) << 48 |
546                 ul(buf[index + 2]) << 40 |
547                 ul(buf[index + 3]) << 32 |
548                 ul(buf[index + 4]) << 24 |
549                 ul(buf[index + 5]) << 16 |
550                 ul(buf[index + 6]) << 8 |
551                 ul(buf[index + 7]);
552         return i;
553     }
554 
555     /***
556      * Sets the NTP timestamp at the given array index.
557      *
558      * @param index index into the byte array.
559      * @param t TimeStamp.
560      */
561     private void setTimestamp(int index, TimeStamp t)
562     {
563         long ntpTime = (t == null) ? 0 : t.ntpValue();
564         // copy 64-bits from Long value into 8 x 8-bit bytes of array
565         // one byte at a time shifting 8-bits for each position.
566         for (int i = 7; i >= 0; i--) {
567             buf[index + i] = (byte) (ntpTime & 0xFF);
568             ntpTime >>>= 8; // shift to next byte
569         }
570         // buf[index] |= 0x80;  // only set if 1900 baseline....
571     }
572 
573     /***
574      * Returns the datagram packet with the NTP details already filled in.
575      *
576      * @return a datagram packet.
577      */
578 //    @Override
579     public synchronized DatagramPacket getDatagramPacket()
580     {
581         if (dp == null) {
582             dp = new DatagramPacket(buf, buf.length);
583             dp.setPort(NTP_PORT);
584         }
585         return dp;
586     }
587 
588     /***
589      * Set the contents of this object from source datagram packet.
590      *
591      * @param srcDp source DatagramPacket to copy contents from, never null.
592      * @throws IllegalArgumentException if srcDp is null or byte length is less than minimum length of 48 bytes
593      */
594 //    @Override
595     public void setDatagramPacket(DatagramPacket srcDp)
596     {
597         if (srcDp == null || srcDp.getLength() < buf.length) {
598             throw new IllegalArgumentException();
599         }
600         byte[] incomingBuf = srcDp.getData();
601         int len = srcDp.getLength();
602         if (len > buf.length) {
603             len = buf.length;
604         }
605         System.arraycopy(incomingBuf, 0, buf, 0, len);
606         DatagramPacket dp = getDatagramPacket();
607         dp.setAddress(srcDp.getAddress());
608         int port = srcDp.getPort();
609         dp.setPort(port > 0 ? port : NTP_PORT);
610         dp.setData(buf);
611     }
612 
613     /***
614      * Compares this object against the specified object.
615      * The result is <code>true</code> if and only if the argument is
616      * not <code>null</code> and is a <code>NtpV3Impl</code> object that
617      * contains the same values as this object.
618      *
619      * @param   obj   the object to compare with.
620      * @return  <code>true</code> if the objects are the same;
621      *          <code>false</code> otherwise.
622      * @since 3.4
623      */
624     @Override
625     public boolean equals(Object obj)
626     {
627         if (this == obj) {
628             return true;
629         }
630         if (obj == null || getClass() != obj.getClass()) {
631             return false;
632         }
633         NtpV3Impl other = (NtpV3Impl) obj;
634         return java.util.Arrays.equals(buf, other.buf);
635     }
636 
637     /***
638      * Computes a hashcode for this object. The result is the exclusive
639      * OR of the values of this object stored as a byte array.
640      *
641      * @return  a hash code value for this object.
642      * @since 3.4
643      */
644     @Override
645     public int hashCode()
646     {
647         return java.util.Arrays.hashCode(buf);
648     }
649 
650     /***
651      * Convert byte to unsigned integer.
652      * Java only has signed types so we have to do
653      * more work to get unsigned ops.
654      *
655      * @param b input byte
656      * @return unsigned int value of byte
657      */
658     protected static final int ui(byte b)
659     {
660         int i = b & 0xFF;
661         return i;
662     }
663 
664     /***
665      * Convert byte to unsigned long.
666      * Java only has signed types so we have to do
667      * more work to get unsigned ops
668      *
669      * @param b input byte
670      * @return unsigned long value of byte
671      */
672     protected static final long ul(byte b)
673     {
674         long i = b & 0xFF;
675         return i;
676     }
677 
678     /***
679      * Returns details of NTP packet as a string.
680      *
681      * @return details of NTP packet as a string.
682      */
683     @Override
684     public String toString()
685     {
686         return "[" +
687                 "version:" + getVersion() +
688                 ", mode:" + getMode() +
689                 ", poll:" + getPoll() +
690                 ", precision:" + getPrecision() +
691                 ", delay:" + getRootDelay() +
692                 ", dispersion(ms):" + getRootDispersionInMillisDouble() +
693                 ", id:" + getReferenceIdString() +
694                 ", xmitTime:" + getTransmitTimeStamp().toDateString() +
695                 " ]";
696     }
697 
698 }