View Javadoc

1   package org.apache.commons.net.ntp;
2   /*
3    * Copyright 2001-2005 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *     http://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  import java.net.DatagramPacket;
18  
19  /***
20   * Implementation of NtpV3Packet with methods converting Java objects to/from
21   * the Network Time Protocol (NTP) data message header format described in RFC-1305.
22   *
23   * @author Naz Irizarry, MITRE Corp
24   * @author Jason Mathews, MITRE Corp
25   *
26   * @version $Revision: 165675 $ $Date: 2005-05-02 15:09:55 -0500 (Mon, 02 May 2005) $
27   */
28  public class NtpV3Impl implements NtpV3Packet
29  {
30  
31      private static final int MODE_INDEX = 0;
32      private static final int MODE_SHIFT = 0;
33  
34      private static final int VERSION_INDEX = 0;
35      private static final int VERSION_SHIFT = 3;
36  
37      private static final int LI_INDEX = 0;
38      private static final int LI_SHIFT = 6;
39  
40      private static final int STRATUM_INDEX = 1;
41      private static final int POLL_INDEX = 2;
42      private static final int PRECISION_INDEX = 3;
43  
44      private static final int ROOT_DELAY_INDEX = 4;
45      private static final int ROOT_DISPERSION_INDEX = 8;
46      private static final int REFERENCE_ID_INDEX = 12;
47  
48      private static final int REFERENCE_TIMESTAMP_INDEX = 16;
49      private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
50      private static final int RECEIVE_TIMESTAMP_INDEX = 32;
51      private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
52  
53      private static final int KEY_IDENTIFIER_INDEX = 48;
54      private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
55  
56      private byte[] buf = new byte[48];
57  
58      private DatagramPacket dp;
59  
60      /** Creates a new instance of NtpV3Impl */
61      public NtpV3Impl()
62      {
63      }
64  
65      /***
66       * Returns mode as defined in RFC-1305 which is a 3-bit integer
67       * whose value is indicated by the MODE_xxx parameters.
68       *
69       * @return mode as defined in RFC-1305.
70       */
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      public String getModeName()
82      {
83          return NtpUtils.getModeName(getMode());
84      }
85  
86      /***
87       * Set mode as defined in RFC-1305.
88       * @param mode
89       */
90      public void setMode(int mode)
91      {
92          buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
93      }
94  
95      /***
96       * Returns leap indicator as defined in RFC-1305 which is a two-bit code:
97       *	0=no warning
98       *	1=last minute has 61 seconds
99       *	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 }