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 * @version $Revision: 1741829 $
026 */
027public class NtpV3Impl implements NtpV3Packet
028{
029
030    private static final int MODE_INDEX = 0;
031    private static final int MODE_SHIFT = 0;
032
033    private static final int VERSION_INDEX = 0;
034    private static final int VERSION_SHIFT = 3;
035
036    private static final int LI_INDEX = 0;
037    private static final int LI_SHIFT = 6;
038
039    private static final int STRATUM_INDEX = 1;
040    private static final int POLL_INDEX = 2;
041    private static final int PRECISION_INDEX = 3;
042
043    private static final int ROOT_DELAY_INDEX = 4;
044    private static final int ROOT_DISPERSION_INDEX = 8;
045    private static final int REFERENCE_ID_INDEX = 12;
046
047    private static final int REFERENCE_TIMESTAMP_INDEX = 16;
048    private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
049    private static final int RECEIVE_TIMESTAMP_INDEX = 32;
050    private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
051
052//    private static final int KEY_IDENTIFIER_INDEX = 48;
053//    private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
054
055    private final byte[] buf = new byte[48];
056
057    private volatile DatagramPacket dp;
058
059    /** Creates a new instance of NtpV3Impl */
060    public NtpV3Impl()
061    {
062    }
063
064    /***
065     * Returns mode as defined in RFC-1305 which is a 3-bit integer
066     * whose value is indicated by the MODE_xxx parameters.
067     *
068     * @return mode as defined in RFC-1305.
069     */
070    @Override
071    public int getMode()
072    {
073        return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
074    }
075
076    /***
077     * Return human-readable name of message mode type as described in
078     * RFC 1305.
079     * @return mode name as string.
080     */
081    @Override
082    public String getModeName()
083    {
084        return NtpUtils.getModeName(getMode());
085    }
086
087    /***
088     * Set mode as defined in RFC-1305.
089     *
090     * @param mode the mode to set
091     */
092    @Override
093    public void setMode(int mode)
094    {
095        buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
096    }
097
098    /***
099     * Returns leap indicator as defined in RFC-1305 which is a two-bit code:
100     *  0=no warning
101     *  1=last minute has 61 seconds
102     *  2=last minute has 59 seconds
103     *  3=alarm condition (clock not synchronized)
104     *
105     * @return leap indicator as defined in RFC-1305.
106     */
107    @Override
108    public int getLeapIndicator()
109    {
110        return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3;
111    }
112
113    /***
114     * Set leap indicator as defined in RFC-1305.
115     *
116     * @param li leap indicator.
117     */
118    @Override
119    public void setLeapIndicator(int li)
120    {
121        buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT));
122    }
123
124    /***
125     * Returns poll interval as defined in RFC-1305, which is an eight-bit
126     * signed integer indicating the maximum interval between successive
127     * messages, in seconds to the nearest power of two (e.g. value of six
128     * indicates an interval of 64 seconds. The values that can appear in
129     * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive.
130     *
131     * @return poll interval as defined in RFC-1305.
132     */
133    @Override
134    public int getPoll()
135    {
136        return buf[POLL_INDEX];
137    }
138
139    /***
140     * Set poll interval as defined in RFC-1305.
141     *
142     * @param poll poll interval.
143     */
144    @Override
145    public void setPoll(int poll)
146    {
147        buf[POLL_INDEX] = (byte) (poll & 0xFF);
148    }
149
150    /***
151     * Returns precision as defined in RFC-1305 encoded as an 8-bit signed
152     * integer (seconds to nearest power of two).
153     * Values normally range from -6 to -20.
154     *
155     * @return precision as defined in RFC-1305.
156     */
157    @Override
158    public int getPrecision()
159    {
160        return buf[PRECISION_INDEX];
161    }
162
163    /***
164     * Set precision as defined in RFC-1305.
165     * @param precision the precision to set
166     * @since 3.4
167     */
168    @Override
169    public void setPrecision(int precision)
170    {
171        buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
172    }
173
174    /***
175     * Returns NTP version number as defined in RFC-1305.
176     *
177     * @return NTP version number.
178     */
179    @Override
180    public int getVersion()
181    {
182        return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7;
183    }
184
185    /***
186     * Set NTP version as defined in RFC-1305.
187     *
188     * @param version NTP version.
189     */
190    @Override
191    public void setVersion(int version)
192    {
193        buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT));
194    }
195
196    /***
197     * Returns Stratum as defined in RFC-1305, which indicates the stratum level
198     * of the local clock, with values defined as follows: 0=unspecified,
199     * 1=primary ref clock, and all others a secondary reference (via NTP).
200     *
201     * @return Stratum level as defined in RFC-1305.
202     */
203    @Override
204    public int getStratum()
205    {
206        return ui(buf[STRATUM_INDEX]);
207    }
208
209    /***
210     * Set stratum level as defined in RFC-1305.
211     *
212     * @param stratum stratum level.
213     */
214    @Override
215    public void setStratum(int stratum)
216    {
217        buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
218    }
219
220    /***
221     * Return root delay as defined in RFC-1305, which is the total roundtrip delay
222     * 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    {
230        return getInt(ROOT_DELAY_INDEX);
231    }
232
233    /***
234     * Set root delay as defined in RFC-1305.
235     *
236     * @param delay root delay
237     * @since 3.4
238     */
239    @Override
240    public void setRootDelay(int delay)
241    {
242        setInt(ROOT_DELAY_INDEX, delay);
243    }
244
245    /**
246     * Return root delay as defined in RFC-1305 in milliseconds, which is
247     * the total roundtrip delay to the primary reference source, in
248     * seconds. Values can take positive and negative values, depending
249     * on clock precision and skew.
250     *
251     * @return root delay in milliseconds
252     */
253    @Override
254    public double getRootDelayInMillisDouble()
255    {
256        double l = getRootDelay();
257        return l / 65.536;
258    }
259
260    /***
261     * Returns root dispersion as defined in RFC-1305.
262     * @return root dispersion.
263     */
264    @Override
265    public int getRootDispersion()
266    {
267        return getInt(ROOT_DISPERSION_INDEX);
268    }
269
270    /***
271     * Set root dispersion as defined in RFC-1305.
272     *
273     * @param dispersion root dispersion
274     * @since 3.4
275     */
276    @Override
277    public void setRootDispersion(int dispersion)
278    {
279        setInt(ROOT_DISPERSION_INDEX, dispersion);
280    }
281
282    /***
283     * Returns root dispersion (as defined in RFC-1305) in milliseconds.
284     *
285     * @return root dispersion in milliseconds
286     */
287    @Override
288    public long getRootDispersionInMillis()
289    {
290        long l = getRootDispersion();
291        return (l * 1000) / 65536L;
292    }
293
294    /***
295     * Returns root dispersion (as defined in RFC-1305) in milliseconds
296     * as double precision value.
297     *
298     * @return root dispersion in milliseconds
299     */
300    @Override
301    public double getRootDispersionInMillisDouble()
302    {
303        double l = getRootDispersion();
304        return l / 65.536;
305    }
306
307    /***
308     * Set reference clock identifier field with 32-bit unsigned integer value.
309     * See RFC-1305 for description.
310     *
311     * @param refId reference clock identifier.
312     */
313    @Override
314    public void setReferenceId(int refId)
315    {
316        setInt(REFERENCE_ID_INDEX, refId);
317    }
318
319    /***
320     * Returns the reference id as defined in RFC-1305, which is
321     * a 32-bit integer whose value is dependent on several criteria.
322     *
323     * @return the reference id as defined in RFC-1305.
324     */
325    @Override
326    public int getReferenceId()
327    {
328        return getInt(REFERENCE_ID_INDEX);
329    }
330
331    /***
332     * Returns the reference id string. String cannot be null but
333     * value is dependent on the version of the NTP spec supported
334     * and stratum level. Value can be an empty string, clock type string,
335     * IP address, or a hex string.
336     *
337     * @return the reference id string.
338     */
339    @Override
340    public String getReferenceIdString()
341    {
342        int version = getVersion();
343        int stratum = getStratum();
344        if (version == VERSION_3 || version == VERSION_4) {
345            if (stratum == 0 || stratum == 1) {
346                return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
347            }
348            // in NTPv4 servers this is latest transmit timestamp of ref source
349            if (version == VERSION_4) {
350                return idAsHex();
351            }
352        }
353
354        // Stratum 2 and higher this is a four-octet IPv4 address
355        // of the primary reference host.
356        if (stratum >= 2) {
357            return idAsIPAddress();
358        }
359        return idAsHex();
360    }
361
362    /***
363     * Returns Reference id as dotted IP address.
364     * @return refId as IP address string.
365     */
366    private String idAsIPAddress()
367    {
368        return ui(buf[REFERENCE_ID_INDEX]) + "." +
369                ui(buf[REFERENCE_ID_INDEX + 1]) + "." +
370                ui(buf[REFERENCE_ID_INDEX + 2]) + "." +
371                ui(buf[REFERENCE_ID_INDEX + 3]);
372    }
373
374    private String idAsString()
375    {
376        StringBuilder id = new StringBuilder();
377        for (int i = 0; i <= 3; i++) {
378            char c = (char) buf[REFERENCE_ID_INDEX + i];
379            if (c == 0) {  // 0-terminated string
380                break;
381            }
382            id.append(c);
383        }
384        return id.toString();
385    }
386
387    private String idAsHex()
388    {
389        return Integer.toHexString(getReferenceId());
390    }
391
392    /***
393     * Returns the transmit timestamp as defined in RFC-1305.
394     *
395     * @return the transmit timestamp as defined in RFC-1305.
396     * Never returns a null object.
397     */
398    @Override
399    public TimeStamp getTransmitTimeStamp()
400    {
401        return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
402    }
403
404    /***
405     * Set transmit time with NTP timestamp.
406     * If <code>ts</code> is null then zero time is used.
407     *
408     * @param ts NTP timestamp
409     */
410    @Override
411    public void setTransmitTime(TimeStamp ts)
412    {
413        setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
414    }
415
416    /***
417     * Set originate timestamp given NTP TimeStamp object.
418     * If <code>ts</code> is null then zero time is used.
419     *
420     * @param ts NTP timestamp
421     */
422    @Override
423    public void setOriginateTimeStamp(TimeStamp ts)
424    {
425        setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
426    }
427
428    /***
429     * Returns the originate time as defined in RFC-1305.
430     *
431     * @return the originate time.
432     * Never returns null.
433     */
434    @Override
435    public TimeStamp getOriginateTimeStamp()
436    {
437        return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
438    }
439
440    /***
441     * Returns the reference time as defined in RFC-1305.
442     *
443     * @return the reference time as <code>TimeStamp</code> object.
444     * Never returns null.
445     */
446    @Override
447    public TimeStamp getReferenceTimeStamp()
448    {
449        return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
450    }
451
452    /***
453     * Set Reference time with NTP timestamp. If <code>ts</code> is null
454     * then zero time is used.
455     *
456     * @param ts NTP timestamp
457     */
458    @Override
459    public void setReferenceTime(TimeStamp ts)
460    {
461        setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
462    }
463
464    /***
465     * Returns receive timestamp as defined in RFC-1305.
466     *
467     * @return the receive time.
468     * Never returns null.
469     */
470    @Override
471    public TimeStamp getReceiveTimeStamp()
472    {
473        return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
474    }
475
476    /***
477     * Set receive timestamp given NTP TimeStamp object.
478     * If <code>ts</code> is null then zero time is used.
479     *
480     * @param ts timestamp
481     */
482    @Override
483    public void setReceiveTimeStamp(TimeStamp ts)
484    {
485        setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
486    }
487
488    /***
489     * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
490     * correspond to the protocol used to obtain the timing information.
491     *
492     * @return packet type string identifier which in this case is "NTP".
493     */
494    @Override
495    public String getType()
496    {
497        return "NTP";
498    }
499
500    /***
501     * @return 4 bytes as 32-bit int
502     */
503    private int getInt(int index)
504    {
505        int i = ui(buf[index]) << 24 |
506                ui(buf[index + 1]) << 16 |
507                ui(buf[index + 2]) << 8 |
508                ui(buf[index + 3]);
509
510        return i;
511    }
512
513    /***
514     * Set integer value at index position.
515     *
516     * @param idx index position
517     * @param value 32-bit int value
518     */
519    private void setInt(int idx, int value)
520    {
521        for (int i=3; i >= 0; i--) {
522            buf[idx + i] = (byte) (value & 0xff);
523            value >>>= 8; // shift right one-byte
524        }
525    }
526
527    /**
528     * Get NTP Timestamp at specified starting index.
529     *
530     * @param index index into data array
531     * @return TimeStamp object for 64 bits starting at index
532     */
533    private TimeStamp getTimestamp(int index)
534    {
535        return new TimeStamp(getLong(index));
536    }
537
538    /***
539     * Get Long value represented by bits starting at specified index.
540     *
541     * @return 8 bytes as 64-bit long
542     */
543    private long getLong(int index)
544    {
545        long i = ul(buf[index]) << 56 |
546                ul(buf[index + 1]) << 48 |
547                ul(buf[index + 2]) << 40 |
548                ul(buf[index + 3]) << 32 |
549                ul(buf[index + 4]) << 24 |
550                ul(buf[index + 5]) << 16 |
551                ul(buf[index + 6]) << 8 |
552                ul(buf[index + 7]);
553        return i;
554    }
555
556    /***
557     * Sets the NTP timestamp at the given array index.
558     *
559     * @param index index into the byte array.
560     * @param t TimeStamp.
561     */
562    private void setTimestamp(int index, TimeStamp t)
563    {
564        long ntpTime = (t == null) ? 0 : t.ntpValue();
565        // copy 64-bits from Long value into 8 x 8-bit bytes of array
566        // one byte at a time shifting 8-bits for each position.
567        for (int i = 7; i >= 0; i--) {
568            buf[index + i] = (byte) (ntpTime & 0xFF);
569            ntpTime >>>= 8; // shift to next byte
570        }
571        // buf[index] |= 0x80;  // only set if 1900 baseline....
572    }
573
574    /***
575     * Returns the datagram packet with the NTP details already filled in.
576     *
577     * @return a datagram packet.
578     */
579    @Override
580    public synchronized DatagramPacket getDatagramPacket()
581    {
582        if (dp == null) {
583            dp = new DatagramPacket(buf, buf.length);
584            dp.setPort(NTP_PORT);
585        }
586        return dp;
587    }
588
589    /***
590     * Set the contents of this object from source datagram packet.
591     *
592     * @param srcDp source DatagramPacket to copy contents from, never null.
593     * @throws IllegalArgumentException if srcDp is null or byte length is less than minimum length of 48 bytes
594     */
595    @Override
596    public void setDatagramPacket(DatagramPacket srcDp)
597    {
598        if (srcDp == null || srcDp.getLength() < buf.length) {
599            throw new IllegalArgumentException();
600        }
601        byte[] incomingBuf = srcDp.getData();
602        int len = srcDp.getLength();
603        if (len > buf.length) {
604            len = buf.length;
605        }
606        System.arraycopy(incomingBuf, 0, buf, 0, len);
607        DatagramPacket dp = getDatagramPacket();
608        dp.setAddress(srcDp.getAddress());
609        int port = srcDp.getPort();
610        dp.setPort(port > 0 ? port : NTP_PORT);
611        dp.setData(buf);
612    }
613
614    /***
615     * Compares this object against the specified object.
616     * The result is <code>true</code> if and only if the argument is
617     * not <code>null</code> and is a <code>NtpV3Impl</code> object that
618     * contains the same values as this object.
619     *
620     * @param   obj   the object to compare with.
621     * @return  <code>true</code> if the objects are the same;
622     *          <code>false</code> otherwise.
623     * @since 3.4
624     */
625    @Override
626    public boolean equals(Object obj)
627    {
628        if (this == obj) {
629            return true;
630        }
631        if (obj == null || getClass() != obj.getClass()) {
632            return false;
633        }
634        NtpV3Impl other = (NtpV3Impl) obj;
635        return java.util.Arrays.equals(buf, other.buf);
636    }
637
638    /***
639     * Computes a hashcode for this object. The result is the exclusive
640     * OR of the values of this object stored as a byte array.
641     *
642     * @return  a hash code value for this object.
643     * @since 3.4
644     */
645    @Override
646    public int hashCode()
647    {
648        return java.util.Arrays.hashCode(buf);
649    }
650
651    /***
652     * Convert byte to unsigned integer.
653     * Java only has signed types so we have to do
654     * more work to get unsigned ops.
655     *
656     * @param b input byte
657     * @return unsigned int value of byte
658     */
659    protected static final int ui(byte b)
660    {
661        int i = b & 0xFF;
662        return i;
663    }
664
665    /***
666     * Convert byte to unsigned long.
667     * Java only has signed types so we have to do
668     * more work to get unsigned ops
669     *
670     * @param b input byte
671     * @return unsigned long value of byte
672     */
673    protected static final long ul(byte b)
674    {
675        long i = b & 0xFF;
676        return i;
677    }
678
679    /***
680     * Returns details of NTP packet as a string.
681     *
682     * @return details of NTP packet as a string.
683     */
684    @Override
685    public String toString()
686    {
687        return "[" +
688                "version:" + getVersion() +
689                ", mode:" + getMode() +
690                ", poll:" + getPoll() +
691                ", precision:" + getPrecision() +
692                ", delay:" + getRootDelay() +
693                ", dispersion(ms):" + getRootDispersionInMillisDouble() +
694                ", id:" + getReferenceIdString() +
695                ", xmitTime:" + getTransmitTimeStamp().toDateString() +
696                " ]";
697    }
698
699}