    001package org.apache.commons.net.ntp;
    002/*
    003 * Licensed to the Apache Software Foundation (ASF) under one or more
    004 * contributor license agreements.  See the NOTICE file distributed with
    005 * this work for additional information regarding copyright ownership.
    006 * The ASF licenses this file to You under the Apache License, Version 2.0
    007 * (the "License"); you may not use this file except in compliance with
    008 * the License.  You may obtain a copy of the License at
    009 *
    010 *      http://www.apache.org/licenses/LICENSE-2.0
    011 *
    012 * Unless required by applicable law or agreed to in writing, software
    013 * distributed under the License is distributed on an "AS IS" BASIS,
    014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    015 * See the License for the specific language governing permissions and
    016 * limitations under the License.
    017 */
    018
    019import java.net.DatagramPacket;
    020
    021/***
    022 * Implementation of NtpV3Packet with methods converting Java objects to/from
    023 * the Network Time Protocol (NTP) data message header format described in RFC-1305.
    024 *
    025 * @author Naz Irizarry, MITRE Corp
    026 * @author Jason Mathews, MITRE Corp
    027 *
    028 * @version $Revision: 1489361 $
    029 */
    030public class NtpV3Impl implements NtpV3Packet
    031{
    032
    033    private static final int MODE_INDEX = 0;
    034    private static final int MODE_SHIFT = 0;
    035
    036    private static final int VERSION_INDEX = 0;
    037    private static final int VERSION_SHIFT = 3;
    038
    039    private static final int LI_INDEX = 0;
    040    private static final int LI_SHIFT = 6;
    041
    042    private static final int STRATUM_INDEX = 1;
    043    private static final int POLL_INDEX = 2;
    044    private static final int PRECISION_INDEX = 3;
    045
    046    private static final int ROOT_DELAY_INDEX = 4;
    047    private static final int ROOT_DISPERSION_INDEX = 8;
    048    private static final int REFERENCE_ID_INDEX = 12;
    049
    050    private static final int REFERENCE_TIMESTAMP_INDEX = 16;
    051    private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
    052    private static final int RECEIVE_TIMESTAMP_INDEX = 32;
    053    private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
    054
    055//    private static final int KEY_IDENTIFIER_INDEX = 48;
    056//    private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
    057
    058    private final byte[] buf = new byte[48];
    059
    060    private volatile DatagramPacket dp;
    061
    062    /** Creates a new instance of NtpV3Impl */
    063    public NtpV3Impl()
    064    {
    065    }
    066
    067    /***
    068     * Returns mode as defined in RFC-1305 which is a 3-bit integer
    069     * whose value is indicated by the MODE_xxx parameters.
    070     *
    071     * @return mode as defined in RFC-1305.
    072     */
    073//    @Override
    074    public int getMode()
    075    {
    076        return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
    077    }
    078
    079    /***
    080     * Return human-readable name of message mode type as described in
    081     * RFC 1305.
    082     * @return mode name as string.
    083     */
    084//    @Override
    085    public String getModeName()
    086    {
    087        return NtpUtils.getModeName(getMode());
    088    }
    089
    090    /***
    091     * Set mode as defined in RFC-1305.
    092     * @param mode
    093     */
    094//    @Override
    095    public void setMode(int mode)
    096    {
    097        buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
    098    }
    099
    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}