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 21:09:55 +0100 (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 }