NtpV3Impl.java

  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.  *      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. package org.apache.commons.net.ntp;

  18. import java.net.DatagramPacket;

  19. /**
  20.  * Implements {@link NtpV3Packet} to convert Java objects to and from the Network Time Protocol (NTP) data message header format described in RFC-1305.
  21.  */
  22. public class NtpV3Impl implements NtpV3Packet {

  23.     private static final int MODE_INDEX = 0;
  24.     private static final int MODE_SHIFT = 0;

  25.     private static final int VERSION_INDEX = 0;
  26.     private static final int VERSION_SHIFT = 3;

  27.     private static final int LI_INDEX = 0;
  28.     private static final int LI_SHIFT = 6;

  29.     private static final int STRATUM_INDEX = 1;
  30.     private static final int POLL_INDEX = 2;
  31.     private static final int PRECISION_INDEX = 3;

  32.     private static final int ROOT_DELAY_INDEX = 4;
  33.     private static final int ROOT_DISPERSION_INDEX = 8;
  34.     private static final int REFERENCE_ID_INDEX = 12;

  35.     private static final int REFERENCE_TIMESTAMP_INDEX = 16;
  36.     private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
  37.     private static final int RECEIVE_TIMESTAMP_INDEX = 32;
  38.     private static final int TRANSMIT_TIMESTAMP_INDEX = 40;

  39. //    private static final int KEY_IDENTIFIER_INDEX = 48;
  40. //    private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */

  41.     /**
  42.      * Convert byte to unsigned integer. Java only has signed types, so we have to do more work to get unsigned ops.
  43.      *
  44.      * @param b input byte
  45.      * @return unsigned int value of byte
  46.      */
  47.     protected static final int ui(final byte b) {
  48.         return b & 0xFF;
  49.     }

  50.     /**
  51.      * Convert byte to unsigned long. Java only has signed types, so we have to do more work to get unsigned ops
  52.      *
  53.      * @param b input byte
  54.      * @return unsigned long value of byte
  55.      */
  56.     protected static final long ul(final byte b) {
  57.         return b & 0xFF;
  58.     }

  59.     private final byte[] buf = new byte[48];

  60.     private volatile DatagramPacket dp;

  61.     /** Creates a new instance of NtpV3Impl */
  62.     public NtpV3Impl() {
  63.     }

  64.     /**
  65.      * 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
  66.      * <code>NtpV3Impl</code> object that contains the same values as this object.
  67.      *
  68.      * @param obj the object to compare with.
  69.      * @return {@code true} if the objects are the same; {@code false} otherwise.
  70.      * @since 3.4
  71.      */
  72.     @Override
  73.     public boolean equals(final Object obj) {
  74.         if (this == obj) {
  75.             return true;
  76.         }
  77.         if (obj == null || getClass() != obj.getClass()) {
  78.             return false;
  79.         }
  80.         final NtpV3Impl other = (NtpV3Impl) obj;
  81.         return java.util.Arrays.equals(buf, other.buf);
  82.     }

  83.     /**
  84.      * Returns the datagram packet with the NTP details already filled in.
  85.      *
  86.      * @return a datagram packet.
  87.      */
  88.     @Override
  89.     public synchronized DatagramPacket getDatagramPacket() {
  90.         if (dp == null) {
  91.             dp = new DatagramPacket(buf, buf.length);
  92.             dp.setPort(NTP_PORT);
  93.         }
  94.         return dp;
  95.     }

  96.     /**
  97.      * @return 4 bytes as 32-bit int
  98.      */
  99.     private int getInt(final int index) {
  100.         return ui(buf[index]) << 24 | ui(buf[index + 1]) << 16 | ui(buf[index + 2]) << 8 | ui(buf[index + 3]);
  101.     }

  102.     /**
  103.      * Returns 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
  104.      * condition (clock not synchronized)
  105.      *
  106.      * @return leap indicator as defined in RFC-1305.
  107.      */
  108.     @Override
  109.     public int getLeapIndicator() {
  110.         return ui(buf[LI_INDEX]) >> LI_SHIFT & 0x3;
  111.     }

  112.     /**
  113.      * Gets Long value represented by bits starting at specified index.
  114.      *
  115.      * @return 8 bytes as 64-bit long
  116.      */
  117.     private long getLong(final int index) {
  118.         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
  119.                 | ul(buf[index + 5]) << 16 | ul(buf[index + 6]) << 8 | ul(buf[index + 7]);
  120.     }

  121.     /**
  122.      * Returns mode as defined in RFC-1305 which is a 3-bit integer whose value is indicated by the MODE_xxx parameters.
  123.      *
  124.      * @return mode as defined in RFC-1305.
  125.      */
  126.     @Override
  127.     public int getMode() {
  128.         return ui(buf[MODE_INDEX]) >> MODE_SHIFT & 0x7;
  129.     }

  130.     /**
  131.      * Return human-readable name of message mode type as described in RFC 1305.
  132.      *
  133.      * @return mode name as string.
  134.      */
  135.     @Override
  136.     public String getModeName() {
  137.         return NtpUtils.getModeName(getMode());
  138.     }

  139.     /**
  140.      * Returns the {@code originate} time as defined in RFC-1305.
  141.      *
  142.      * @return the {@code originate} time. Never returns null.
  143.      */
  144.     @Override
  145.     public TimeStamp getOriginateTimeStamp() {
  146.         return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
  147.     }

  148.     /**
  149.      * Returns poll interval as defined in RFC-1305, which is an eight-bit signed integer indicating the maximum interval between successive messages, in
  150.      * 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
  151.      * NTP_MINPOLL to NTP_MAXPOLL inclusive.
  152.      *
  153.      * @return poll interval as defined in RFC-1305.
  154.      */
  155.     @Override
  156.     public int getPoll() {
  157.         return buf[POLL_INDEX];
  158.     }

  159.     /**
  160.      * Returns 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.
  161.      *
  162.      * @return precision as defined in RFC-1305.
  163.      */
  164.     @Override
  165.     public int getPrecision() {
  166.         return buf[PRECISION_INDEX];
  167.     }

  168.     /**
  169.      * Returns {@code receive} timestamp as defined in RFC-1305.
  170.      *
  171.      * @return the {@code receive} time. Never returns null.
  172.      */
  173.     @Override
  174.     public TimeStamp getReceiveTimeStamp() {
  175.         return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
  176.     }

  177.     /**
  178.      * Returns the reference id as defined in RFC-1305, which is a 32-bit integer whose value is dependent on several criteria.
  179.      *
  180.      * @return the reference id as defined in RFC-1305.
  181.      */
  182.     @Override
  183.     public int getReferenceId() {
  184.         return getInt(REFERENCE_ID_INDEX);
  185.     }

  186.     /**
  187.      * Returns 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
  188.      * empty string, clock type string, IP address, or a hexadecimal string.
  189.      *
  190.      * @return the reference id string.
  191.      */
  192.     @Override
  193.     public String getReferenceIdString() {
  194.         final int version = getVersion();
  195.         final int stratum = getStratum();
  196.         if (version == VERSION_3 || version == VERSION_4) {
  197.             if (stratum == 0 || stratum == 1) {
  198.                 return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
  199.             }
  200.             // in NTPv4 servers this is latest transmit timestamp of ref source
  201.             if (version == VERSION_4) {
  202.                 return idAsHex();
  203.             }
  204.         }

  205.         // Stratum 2 and higher this is a four-octet IPv4 address
  206.         // of the primary reference host.
  207.         if (stratum >= 2) {
  208.             return idAsIPAddress();
  209.         }
  210.         return idAsHex();
  211.     }

  212.     /**
  213.      * Returns the reference time as defined in RFC-1305.
  214.      *
  215.      * @return the reference time as <code>TimeStamp</code> object. Never returns null.
  216.      */
  217.     @Override
  218.     public TimeStamp getReferenceTimeStamp() {
  219.         return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
  220.     }

  221.     /**
  222.      * Return 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
  223.      * negative values, depending on clock precision and skew.
  224.      *
  225.      * @return root delay as defined in RFC-1305.
  226.      */
  227.     @Override
  228.     public int getRootDelay() {
  229.         return getInt(ROOT_DELAY_INDEX);
  230.     }

  231.     /**
  232.      * Return root delay as defined in RFC-1305 in milliseconds, which is the total roundtrip delay to the primary reference source, in seconds. Values can take
  233.      * positive and negative values, depending on clock precision and skew.
  234.      *
  235.      * @return root delay in milliseconds
  236.      */
  237.     @Override
  238.     public double getRootDelayInMillisDouble() {
  239.         final double l = getRootDelay();
  240.         return l / 65.536;
  241.     }

  242.     /**
  243.      * Returns root dispersion as defined in RFC-1305.
  244.      *
  245.      * @return root dispersion.
  246.      */
  247.     @Override
  248.     public int getRootDispersion() {
  249.         return getInt(ROOT_DISPERSION_INDEX);
  250.     }

  251.     /**
  252.      * Returns root dispersion (as defined in RFC-1305) in milliseconds.
  253.      *
  254.      * @return root dispersion in milliseconds
  255.      */
  256.     @Override
  257.     public long getRootDispersionInMillis() {
  258.         final long l = getRootDispersion();
  259.         return l * 1000 / 65536L;
  260.     }

  261.     /**
  262.      * Returns root dispersion (as defined in RFC-1305) in milliseconds as double precision value.
  263.      *
  264.      * @return root dispersion in milliseconds
  265.      */
  266.     @Override
  267.     public double getRootDispersionInMillisDouble() {
  268.         final double l = getRootDispersion();
  269.         return l / 65.536;
  270.     }

  271.     /**
  272.      * Returns Stratum as defined in RFC-1305, which indicates the stratum level of the local clock, with values defined as follows: 0=unspecified, 1=primary
  273.      * ref clock, and all others a secondary reference (via NTP).
  274.      *
  275.      * @return Stratum level as defined in RFC-1305.
  276.      */
  277.     @Override
  278.     public int getStratum() {
  279.         return ui(buf[STRATUM_INDEX]);
  280.     }

  281.     /**
  282.      * Gets NTP Timestamp at specified starting index.
  283.      *
  284.      * @param index index into data array
  285.      * @return TimeStamp object for 64 bits starting at index
  286.      */
  287.     private TimeStamp getTimestamp(final int index) {
  288.         return new TimeStamp(getLong(index));
  289.     }

  290.     /**
  291.      * Returns the {@code transmit} timestamp as defined in RFC-1305.
  292.      *
  293.      * @return the {@code transmit} timestamp as defined in RFC-1305. Never returns a null object.
  294.      */
  295.     @Override
  296.     public TimeStamp getTransmitTimeStamp() {
  297.         return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
  298.     }

  299.     /**
  300.      * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) correspond to the protocol used to obtain the timing information.
  301.      *
  302.      * @return packet type string identifier which in this case is "NTP".
  303.      */
  304.     @Override
  305.     public String getType() {
  306.         return "NTP";
  307.     }

  308.     /**
  309.      * Returns NTP version number as defined in RFC-1305.
  310.      *
  311.      * @return NTP version number.
  312.      */
  313.     @Override
  314.     public int getVersion() {
  315.         return ui(buf[VERSION_INDEX]) >> VERSION_SHIFT & 0x7;
  316.     }

  317.     /**
  318.      * Computes a hash code for this object. The result is the exclusive OR of the values of this object stored as a byte array.
  319.      *
  320.      * @return a hash code value for this object.
  321.      * @since 3.4
  322.      */
  323.     @Override
  324.     public int hashCode() {
  325.         return java.util.Arrays.hashCode(buf);
  326.     }

  327.     private String idAsHex() {
  328.         return Integer.toHexString(getReferenceId());
  329.     }

  330.     /**
  331.      * Returns Reference id as dotted IP address.
  332.      *
  333.      * @return refId as IP address string.
  334.      */
  335.     private String idAsIPAddress() {
  336.         return ui(buf[REFERENCE_ID_INDEX]) + "." + ui(buf[REFERENCE_ID_INDEX + 1]) + "." + ui(buf[REFERENCE_ID_INDEX + 2]) + "."
  337.                 + ui(buf[REFERENCE_ID_INDEX + 3]);
  338.     }

  339.     private String idAsString() {
  340.         final StringBuilder id = new StringBuilder();
  341.         for (int i = 0; i <= 3; i++) {
  342.             final char c = (char) buf[REFERENCE_ID_INDEX + i];
  343.             if (c == 0) { // 0-terminated string
  344.                 break;
  345.             }
  346.             id.append(c);
  347.         }
  348.         return id.toString();
  349.     }

  350.     /**
  351.      * Sets the contents of this object from source datagram packet.
  352.      *
  353.      * @param srcDp source DatagramPacket to copy contents from, never null.
  354.      * @throws IllegalArgumentException if srcDp is null or byte length is less than minimum length of 48 bytes
  355.      */
  356.     @Override
  357.     public void setDatagramPacket(final DatagramPacket srcDp) {
  358.         if (srcDp == null || srcDp.getLength() < buf.length) {
  359.             throw new IllegalArgumentException();
  360.         }
  361.         final byte[] incomingBuf = srcDp.getData();
  362.         int len = srcDp.getLength();
  363.         if (len > buf.length) {
  364.             len = buf.length;
  365.         }
  366.         System.arraycopy(incomingBuf, 0, buf, 0, len);
  367.         final DatagramPacket dp = getDatagramPacket();
  368.         dp.setAddress(srcDp.getAddress());
  369.         final int port = srcDp.getPort();
  370.         dp.setPort(port > 0 ? port : NTP_PORT);
  371.         dp.setData(buf);
  372.     }

  373.     /**
  374.      * Sets integer value at index position.
  375.      *
  376.      * @param idx   index position
  377.      * @param value 32-bit int value
  378.      */
  379.     private void setInt(final int idx, int value) {
  380.         for (int i = 3; i >= 0; i--) {
  381.             buf[idx + i] = (byte) (value & 0xff);
  382.             value >>>= 8; // shift right one-byte
  383.         }
  384.     }

  385.     /**
  386.      * Sets leap indicator as defined in RFC-1305.
  387.      *
  388.      * @param li leap indicator.
  389.      */
  390.     @Override
  391.     public void setLeapIndicator(final int li) {
  392.         buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | (li & 0x3) << LI_SHIFT);
  393.     }

  394.     /**
  395.      * Sets mode as defined in RFC-1305.
  396.      *
  397.      * @param mode the mode to set
  398.      */
  399.     @Override
  400.     public void setMode(final int mode) {
  401.         buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
  402.     }

  403.     /**
  404.      * Sets originate timestamp given NTP TimeStamp object. If <code>ts</code> is null then zero time is used.
  405.      *
  406.      * @param ts NTP timestamp
  407.      */
  408.     @Override
  409.     public void setOriginateTimeStamp(final TimeStamp ts) {
  410.         setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
  411.     }

  412.     /**
  413.      * Sets poll interval as defined in RFC-1305.
  414.      *
  415.      * @param poll poll interval.
  416.      */
  417.     @Override
  418.     public void setPoll(final int poll) {
  419.         buf[POLL_INDEX] = (byte) (poll & 0xFF);
  420.     }

  421.     /**
  422.      * Sets precision as defined in RFC-1305.
  423.      *
  424.      * @param precision the precision to set
  425.      * @since 3.4
  426.      */
  427.     @Override
  428.     public void setPrecision(final int precision) {
  429.         buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
  430.     }

  431.     /**
  432.      * Sets receive timestamp given NTP TimeStamp object. If <code>ts</code> is null then zero time is used.
  433.      *
  434.      * @param ts timestamp
  435.      */
  436.     @Override
  437.     public void setReceiveTimeStamp(final TimeStamp ts) {
  438.         setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
  439.     }

  440.     /**
  441.      * Sets reference clock identifier field with 32-bit unsigned integer value. See RFC-1305 for description.
  442.      *
  443.      * @param refId reference clock identifier.
  444.      */
  445.     @Override
  446.     public void setReferenceId(final int refId) {
  447.         setInt(REFERENCE_ID_INDEX, refId);
  448.     }

  449.     /**
  450.      * Sets Reference time with NTP timestamp. If <code>ts</code> is null then zero time is used.
  451.      *
  452.      * @param ts NTP timestamp
  453.      */
  454.     @Override
  455.     public void setReferenceTime(final TimeStamp ts) {
  456.         setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
  457.     }

  458.     /**
  459.      * Sets root delay as defined in RFC-1305.
  460.      *
  461.      * @param delay root delay
  462.      * @since 3.4
  463.      */
  464.     @Override
  465.     public void setRootDelay(final int delay) {
  466.         setInt(ROOT_DELAY_INDEX, delay);
  467.     }

  468.     /**
  469.      * Sets root dispersion as defined in RFC-1305.
  470.      *
  471.      * @param dispersion root dispersion
  472.      * @since 3.4
  473.      */
  474.     @Override
  475.     public void setRootDispersion(final int dispersion) {
  476.         setInt(ROOT_DISPERSION_INDEX, dispersion);
  477.     }

  478.     /**
  479.      * Sets stratum level as defined in RFC-1305.
  480.      *
  481.      * @param stratum stratum level.
  482.      */
  483.     @Override
  484.     public void setStratum(final int stratum) {
  485.         buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
  486.     }

  487.     /**
  488.      * Sets the NTP timestamp at the given array index.
  489.      *
  490.      * @param index index into the byte array.
  491.      * @param t     TimeStamp.
  492.      */
  493.     private void setTimestamp(final int index, final TimeStamp t) {
  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.      * Sets transmit time with NTP timestamp. If <code>ts</code> is null then zero time is used.
  505.      *
  506.      * @param ts NTP timestamp
  507.      */
  508.     @Override
  509.     public void setTransmitTime(final TimeStamp ts) {
  510.         setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
  511.     }

  512.     /**
  513.      * Sets NTP version as defined in RFC-1305.
  514.      *
  515.      * @param version NTP version.
  516.      */
  517.     @Override
  518.     public void setVersion(final int version) {
  519.         buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | (version & 0x7) << VERSION_SHIFT);
  520.     }

  521.     /**
  522.      * Returns details of NTP packet as a string.
  523.      *
  524.      * @return details of NTP packet as a string.
  525.      */
  526.     @Override
  527.     public String toString() {
  528.         return "[" + "version:" + getVersion() + ", mode:" + getMode() + ", poll:" + getPoll() + ", precision:" + getPrecision() + ", delay:" + getRootDelay()
  529.                 + ", dispersion(ms):" + getRootDispersionInMillisDouble() + ", id:" + getReferenceIdString() + ", xmitTime:"
  530.                 + getTransmitTimeStamp().toDateString() + " ]";
  531.     }

  532. }