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   * @author Naz Irizarry, MITRE Corp
26   * @author Jason Mathews, MITRE Corp
27   *
28   * @version $Revision: 1489361 $
29   */
30  public class NtpV3Impl implements NtpV3Packet
31  {
32  
33      private static final int MODE_INDEX = 0;
34      private static final int MODE_SHIFT = 0;
35  
36      private static final int VERSION_INDEX = 0;
37      private static final int VERSION_SHIFT = 3;
38  
39      private static final int LI_INDEX = 0;
40      private static final int LI_SHIFT = 6;
41  
42      private static final int STRATUM_INDEX = 1;
43      private static final int POLL_INDEX = 2;
44      private static final int PRECISION_INDEX = 3;
45  
46      private static final int ROOT_DELAY_INDEX = 4;
47      private static final int ROOT_DISPERSION_INDEX = 8;
48      private static final int REFERENCE_ID_INDEX = 12;
49  
50      private static final int REFERENCE_TIMESTAMP_INDEX = 16;
51      private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
52      private static final int RECEIVE_TIMESTAMP_INDEX = 32;
53      private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
54  
55  //    private static final int KEY_IDENTIFIER_INDEX = 48;
56  //    private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
57  
58      private final byte[] buf = new byte[48];
59  
60      private volatile DatagramPacket dp;
61  
62      /** Creates a new instance of NtpV3Impl */
63      public NtpV3Impl()
64      {
65      }
66  
67      /***
68       * Returns mode as defined in RFC-1305 which is a 3-bit integer
69       * whose value is indicated by the MODE_xxx parameters.
70       *
71       * @return mode as defined in RFC-1305.
72       */
73  //    @Override
74      public int getMode()
75      {
76          return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
77      }
78  
79      /***
80       * Return human-readable name of message mode type as described in
81       * RFC 1305.
82       * @return mode name as string.
83       */
84  //    @Override
85      public String getModeName()
86      {
87          return NtpUtils.getModeName(getMode());
88      }
89  
90      /***
91       * Set mode as defined in RFC-1305.
92       * @param mode
93       */
94  //    @Override
95      public void setMode(int mode)
96      {
97          buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
98      }
99  
100     /***
101      * Returns leap indicator as defined in RFC-1305 which is a two-bit code:
102      *  0=no warning
103      *  1=last minute has 61 seconds
104      *  2=last minute has 59 seconds
105      *  3=alarm condition (clock not synchronized)
106      *
107      * @return leap indicator as defined in RFC-1305.
108      */
109 //    @Override
110     public int getLeapIndicator()
111     {
112         return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3;
113     }
114 
115     /***
116      * Set leap indicator as defined in RFC-1305.
117      * @param li leap indicator.
118      */
119 //    @Override
120     public void setLeapIndicator(int li)
121     {
122         buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT));
123     }
124 
125     /***
126      * Returns poll interval as defined in RFC-1305, which is an eight-bit
127      * signed integer indicating the maximum interval between successive
128      * messages, in seconds to the nearest power of two (e.g. value of six
129      * indicates an interval of 64 seconds. The values that can appear in
130      * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive.
131      *
132      * @return poll interval as defined in RFC-1305.
133      */
134 //    @Override
135     public int getPoll()
136     {
137         return buf[POLL_INDEX];
138     }
139 
140     /***
141      * Set poll interval as defined in RFC-1305.
142      *
143      * @param poll poll interval.
144      */
145 //    @Override
146     public void setPoll(int poll)
147     {
148         buf[POLL_INDEX] = (byte) (poll & 0xFF);
149     }
150 
151     /***
152      * Returns precision as defined in RFC-1305 encoded as an 8-bit signed
153      * integer (seconds to nearest power of two).
154      * Values normally range from -6 to -20.
155      *
156      * @return precision as defined in RFC-1305.
157      */
158 //    @Override
159     public int getPrecision()
160     {
161         return buf[PRECISION_INDEX];
162     }
163 
164     /***
165      * Set precision as defined in RFC-1305.
166      * @param precision
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      * Return root delay as defined in RFC-1305 in milliseconds, which is
234      * the total roundtrip delay to the primary reference source, in
235      * seconds. Values can take positive and negative values, depending
236      * on clock precision and skew.
237      *
238      * @return root delay in milliseconds
239      */
240 //    @Override
241     public double getRootDelayInMillisDouble()
242     {
243         double l = getRootDelay();
244         return l / 65.536;
245     }
246 
247     /***
248      * Returns root dispersion as defined in RFC-1305.
249      * @return root dispersion.
250      */
251 //    @Override
252     public int getRootDispersion()
253     {
254         return getInt(ROOT_DISPERSION_INDEX);
255     }
256 
257     /***
258      * Returns root dispersion (as defined in RFC-1305) in milliseconds.
259      *
260      * @return root dispersion in milliseconds
261      */
262 //    @Override
263     public long getRootDispersionInMillis()
264     {
265         long l = getRootDispersion();
266         return (l * 1000) / 65536L;
267     }
268 
269     /***
270      * Returns root dispersion (as defined in RFC-1305) in milliseconds
271      * as double precision value.
272      *
273      * @return root dispersion in milliseconds
274      */
275 //    @Override
276     public double getRootDispersionInMillisDouble()
277     {
278         double l = getRootDispersion();
279         return l / 65.536;
280     }
281 
282     /***
283      * Set reference clock identifier field with 32-bit unsigned integer value.
284      * See RFC-1305 for description.
285      *
286      * @param refId reference clock identifier.
287      */
288 //    @Override
289     public void setReferenceId(int refId)
290     {
291         for (int i = 3; i >= 0; i--) {
292             buf[REFERENCE_ID_INDEX + i] = (byte) (refId & 0xff);
293             refId >>>= 8; // shift right one-byte
294         }
295     }
296 
297     /***
298      * Returns the reference id as defined in RFC-1305, which is
299      * a 32-bit integer whose value is dependent on several criteria.
300      *
301      * @return the reference id as defined in RFC-1305.
302      */
303 //    @Override
304     public int getReferenceId()
305     {
306         return getInt(REFERENCE_ID_INDEX);
307     }
308 
309     /***
310      * Returns the reference id string. String cannot be null but
311      * value is dependent on the version of the NTP spec supported
312      * and stratum level. Value can be an empty string, clock type string,
313      * IP address, or a hex string.
314      *
315      * @return the reference id string.
316      */
317 //    @Override
318     public String getReferenceIdString()
319     {
320         int version = getVersion();
321         int stratum = getStratum();
322         if (version == VERSION_3 || version == VERSION_4) {
323             if (stratum == 0 || stratum == 1) {
324                 return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
325             }
326             // in NTPv4 servers this is latest transmit timestamp of ref source
327             if (version == VERSION_4) {
328                 return idAsHex();
329             }
330         }
331 
332         // Stratum 2 and higher this is a four-octet IPv4 address
333         // of the primary reference host.
334         if (stratum >= 2) {
335             return idAsIPAddress();
336         }
337         return idAsHex();
338     }
339 
340     /***
341      * Returns Reference id as dotted IP address.
342      * @return refId as IP address string.
343      */
344     private String idAsIPAddress()
345     {
346         return ui(buf[REFERENCE_ID_INDEX]) + "." +
347                 ui(buf[REFERENCE_ID_INDEX + 1]) + "." +
348                 ui(buf[REFERENCE_ID_INDEX + 2]) + "." +
349                 ui(buf[REFERENCE_ID_INDEX + 3]);
350     }
351 
352     private String idAsString()
353     {
354         StringBuilder id = new StringBuilder();
355         for (int i = 0; i <= 3; i++) {
356             char c = (char) buf[REFERENCE_ID_INDEX + i];
357             if (c == 0) {  // 0-terminated string
358                 break;
359             }
360             id.append(c);
361         }
362         return id.toString();
363     }
364 
365     private String idAsHex()
366     {
367         return Integer.toHexString(getReferenceId());
368     }
369 
370     /***
371      * Returns the transmit timestamp as defined in RFC-1305.
372      *
373      * @return the transmit timestamp as defined in RFC-1305.
374      * Never returns a null object.
375      */
376 //    @Override
377     public TimeStamp getTransmitTimeStamp()
378     {
379         return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
380     }
381 
382     /***
383      * Set transmit time with NTP timestamp.
384      * If <code>ts</code> is null then zero time is used.
385      *
386      * @param ts NTP timestamp
387      */
388 //    @Override
389     public void setTransmitTime(TimeStamp ts)
390     {
391         setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
392     }
393 
394     /***
395      * Set originate timestamp given NTP TimeStamp object.
396      * If <code>ts</code> is null then zero time is used.
397      *
398      * @param ts NTP timestamp
399      */
400 //    @Override
401     public void setOriginateTimeStamp(TimeStamp ts)
402     {
403         setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
404     }
405 
406     /***
407      * Returns the originate time as defined in RFC-1305.
408      *
409      * @return the originate time.
410      * Never returns null.
411      */
412 //    @Override
413     public TimeStamp getOriginateTimeStamp()
414     {
415         return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
416     }
417 
418     /***
419      * Returns the reference time as defined in RFC-1305.
420      *
421      * @return the reference time as <code>TimeStamp</code> object.
422      * Never returns null.
423      */
424 //    @Override
425     public TimeStamp getReferenceTimeStamp()
426     {
427         return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
428     }
429 
430     /***
431      * Set Reference time with NTP timestamp. If <code>ts</code> is null
432      * then zero time is used.
433      *
434      * @param ts NTP timestamp
435      */
436 //    @Override
437     public void setReferenceTime(TimeStamp ts)
438     {
439         setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
440     }
441 
442     /***
443      * Returns receive timestamp as defined in RFC-1305.
444      *
445      * @return the receive time.
446      * Never returns null.
447      */
448 //    @Override
449     public TimeStamp getReceiveTimeStamp()
450     {
451         return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
452     }
453 
454     /***
455      * Set receive timestamp given NTP TimeStamp object.
456      * If <code>ts</code> is null then zero time is used.
457      *
458      * @param ts timestamp
459      */
460 //    @Override
461     public void setReceiveTimeStamp(TimeStamp ts)
462     {
463         setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
464     }
465 
466     /***
467      * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
468      * correspond to the protocol used to obtain the timing information.
469      *
470      * @return packet type string identifier which in this case is "NTP".
471      */
472 //    @Override
473     public String getType()
474     {
475         return "NTP";
476     }
477 
478     /***
479      * @return 4 bytes as 32-bit int
480      */
481     private int getInt(int index)
482     {
483         int i = ui(buf[index]) << 24 |
484                 ui(buf[index + 1]) << 16 |
485                 ui(buf[index + 2]) << 8 |
486                 ui(buf[index + 3]);
487 
488         return i;
489     }
490 
491     /***
492      * Get NTP Timestamp at specified starting index.
493      *
494      * @param index index into data array
495      * @return TimeStamp object for 64 bits starting at index
496      */
497     private TimeStamp getTimestamp(int index)
498     {
499         return new TimeStamp(getLong(index));
500     }
501 
502     /***
503      * Get Long value represented by bits starting at specified index.
504      *
505      * @return 8 bytes as 64-bit long
506      */
507     private long getLong(int index)
508     {
509         long i = ul(buf[index]) << 56 |
510                 ul(buf[index + 1]) << 48 |
511                 ul(buf[index + 2]) << 40 |
512                 ul(buf[index + 3]) << 32 |
513                 ul(buf[index + 4]) << 24 |
514                 ul(buf[index + 5]) << 16 |
515                 ul(buf[index + 6]) << 8 |
516                 ul(buf[index + 7]);
517         return i;
518     }
519 
520     /***
521      * Sets the NTP timestamp at the given array index.
522      *
523      * @param index index into the byte array.
524      * @param t TimeStamp.
525      */
526     private void setTimestamp(int index, TimeStamp t)
527     {
528         long ntpTime = (t == null) ? 0 : t.ntpValue();
529         // copy 64-bits from Long value into 8 x 8-bit bytes of array
530         // one byte at a time shifting 8-bits for each position.
531         for (int i = 7; i >= 0; i--) {
532             buf[index + i] = (byte) (ntpTime & 0xFF);
533             ntpTime >>>= 8; // shift to next byte
534         }
535         // buf[index] |= 0x80;  // only set if 1900 baseline....
536     }
537 
538     /***
539      * Returns the datagram packet with the NTP details already filled in.
540      *
541      * @return a datagram packet.
542      */
543 //    @Override
544     public synchronized DatagramPacket getDatagramPacket()
545     {
546         if (dp == null) {
547             dp = new DatagramPacket(buf, buf.length);
548             dp.setPort(NTP_PORT);
549         }
550         return dp;
551     }
552 
553     /***
554      * Set the contents of this object from source datagram packet.
555      *
556      * @param srcDp source DatagramPacket to copy contents from.
557      */
558 //    @Override
559     public void setDatagramPacket(DatagramPacket srcDp)
560     {
561         byte[] incomingBuf = srcDp.getData();
562         int len = srcDp.getLength();
563         if (len > buf.length) {
564             len = buf.length;
565         }
566 
567         System.arraycopy(incomingBuf, 0, buf, 0, len);
568     }
569 
570     /***
571      * Convert byte to unsigned integer.
572      * Java only has signed types so we have to do
573      * more work to get unsigned ops.
574      *
575      * @param b
576      * @return unsigned int value of byte
577      */
578     protected final static int ui(byte b)
579     {
580         int i = b & 0xFF;
581         return i;
582     }
583 
584     /***
585      * Convert byte to unsigned long.
586      * Java only has signed types so we have to do
587      * more work to get unsigned ops
588      *
589      * @param b
590      * @return unsigned long value of byte
591      */
592     protected final static long ul(byte b)
593     {
594         long i = b & 0xFF;
595         return i;
596     }
597 
598     /***
599      * Returns details of NTP packet as a string.
600      *
601      * @return details of NTP packet as a string.
602      */
603     @Override
604     public String toString()
605     {
606         return "[" +
607                 "version:" + getVersion() +
608                 ", mode:" + getMode() +
609                 ", poll:" + getPoll() +
610                 ", precision:" + getPrecision() +
611                 ", delay:" + getRootDelay() +
612                 ", dispersion(ms):" + getRootDispersionInMillisDouble() +
613                 ", id:" + getReferenceIdString() +
614                 ", xmitTime:" + getTransmitTimeStamp().toDateString() +
615                 " ]";
616     }
617 
618 }