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