001: package org.apache.commons.net.ntp;
002:
003: /*
004: * Copyright 2001-2005 The Apache Software Foundation
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * 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: import java.net.DatagramPacket;
019:
020: /***
021: * Implementation of NtpV3Packet with methods converting Java objects to/from
022: * the Network Time Protocol (NTP) data message header format described in RFC-1305.
023: *
024: * @author Naz Irizarry, MITRE Corp
025: * @author Jason Mathews, MITRE Corp
026: *
027: * @version $Revision: 165675 $ $Date: 2005-05-02 15:09:55 -0500 (Mon, 02 May 2005) $
028: */
029: public class NtpV3Impl implements NtpV3Packet {
030:
031: private static final int MODE_INDEX = 0;
032: private static final int MODE_SHIFT = 0;
033:
034: private static final int VERSION_INDEX = 0;
035: private static final int VERSION_SHIFT = 3;
036:
037: private static final int LI_INDEX = 0;
038: private static final int LI_SHIFT = 6;
039:
040: private static final int STRATUM_INDEX = 1;
041: private static final int POLL_INDEX = 2;
042: private static final int PRECISION_INDEX = 3;
043:
044: private static final int ROOT_DELAY_INDEX = 4;
045: private static final int ROOT_DISPERSION_INDEX = 8;
046: private static final int REFERENCE_ID_INDEX = 12;
047:
048: private static final int REFERENCE_TIMESTAMP_INDEX = 16;
049: private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
050: private static final int RECEIVE_TIMESTAMP_INDEX = 32;
051: private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
052:
053: private static final int KEY_IDENTIFIER_INDEX = 48;
054: private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
055:
056: private byte[] buf = new byte[48];
057:
058: private DatagramPacket dp;
059:
060: /** Creates a new instance of NtpV3Impl */
061: public NtpV3Impl() {
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: public int getMode() {
071: return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
072: }
073:
074: /***
075: * Return human-readable name of message mode type as described in
076: * RFC 1305.
077: * @return mode name as string.
078: */
079: public String getModeName() {
080: return NtpUtils.getModeName(getMode());
081: }
082:
083: /***
084: * Set mode as defined in RFC-1305.
085: * @param mode
086: */
087: public void setMode(int mode) {
088: buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
089: }
090:
091: /***
092: * Returns leap indicator as defined in RFC-1305 which is a two-bit code:
093: * 0=no warning
094: * 1=last minute has 61 seconds
095: * 2=last minute has 59 seconds
096: * 3=alarm condition (clock not synchronized)
097: *
098: * @return leap indicator as defined in RFC-1305.
099: */
100: public int getLeapIndicator() {
101: return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3;
102: }
103:
104: /***
105: * Set leap indicator as defined in RFC-1305.
106: * @param li leap indicator.
107: */
108: public void setLeapIndicator(int li) {
109: buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT));
110: }
111:
112: /***
113: * Returns poll interval as defined in RFC-1305, which is an eight-bit
114: * signed integer indicating the maximum interval between successive
115: * messages, in seconds to the nearest power of two (e.g. value of six
116: * indicates an interval of 64 seconds. The values that can appear in
117: * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive.
118: *
119: * @return poll interval as defined in RFC-1305.
120: */
121: public int getPoll() {
122: return (int) (buf[POLL_INDEX]);
123: }
124:
125: /***
126: * Set poll interval as defined in RFC-1305.
127: *
128: * @param poll poll interval.
129: */
130: public void setPoll(int poll) {
131: buf[POLL_INDEX] = (byte) (poll & 0xFF);
132: }
133:
134: /***
135: * Returns precision as defined in RFC-1305 encoded as an 8-bit signed
136: * integer (seconds to nearest power of two).
137: * Values normally range from -6 to -20.
138: *
139: * @return precision as defined in RFC-1305.
140: */
141: public int getPrecision() {
142: return (int) buf[PRECISION_INDEX];
143: }
144:
145: /***
146: * Set precision as defined in RFC-1305.
147: * @param precision
148: */
149: public void setPrecision(int precision) {
150: buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
151: }
152:
153: /***
154: * Returns NTP version number as defined in RFC-1305.
155: *
156: * @return NTP version number.
157: */
158: public int getVersion() {
159: return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7;
160: }
161:
162: /***
163: * Set NTP version as defined in RFC-1305.
164: *
165: * @param version NTP version.
166: */
167: public void setVersion(int version) {
168: buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT));
169: }
170:
171: /***
172: * Returns Stratum as defined in RFC-1305, which indicates the stratum level
173: * of the local clock, with values defined as follows: 0=unspecified,
174: * 1=primary ref clock, and all others a secondary reference (via NTP).
175: *
176: * @return Stratum level as defined in RFC-1305.
177: */
178: public int getStratum() {
179: return ui(buf[STRATUM_INDEX]);
180: }
181:
182: /***
183: * Set stratum level as defined in RFC-1305.
184: *
185: * @param stratum stratum level.
186: */
187: public void setStratum(int stratum) {
188: buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
189: }
190:
191: /***
192: * Return root delay as defined in RFC-1305, which is the total roundtrip delay
193: * to the primary reference source, in seconds. Values can take positive and
194: * negative values, depending on clock precision and skew.
195: *
196: * @return root delay as defined in RFC-1305.
197: */
198: public int getRootDelay() {
199: return getInt(ROOT_DELAY_INDEX);
200: }
201:
202: /***
203: * Return root delay as defined in RFC-1305 in milliseconds, which is
204: * the total roundtrip delay to the primary reference source, in
205: * seconds. Values can take positive and negative values, depending
206: * on clock precision and skew.
207: *
208: * @return root delay in milliseconds
209: */
210: public double getRootDelayInMillisDouble() {
211: double l = getRootDelay();
212: return l / 65.536;
213: }
214:
215: /***
216: * Returns root dispersion as defined in RFC-1305.
217: * @return root dispersion.
218: */
219: public int getRootDispersion() {
220: return getInt(ROOT_DISPERSION_INDEX);
221: }
222:
223: /***
224: * Returns root dispersion (as defined in RFC-1305) in milliseconds.
225: *
226: * @return root dispersion in milliseconds
227: */
228: public long getRootDispersionInMillis() {
229: long l = getRootDispersion();
230: return (l * 1000) / 65536L;
231: }
232:
233: /***
234: * Returns root dispersion (as defined in RFC-1305) in milliseconds
235: * as double precision value.
236: *
237: * @return root dispersion in milliseconds
238: */
239: public double getRootDispersionInMillisDouble() {
240: double l = getRootDispersion();
241: return l / 65.536;
242: }
243:
244: /***
245: * Set reference clock identifier field with 32-bit unsigned integer value.
246: * See RFC-1305 for description.
247: *
248: * @param refId reference clock identifier.
249: */
250: public void setReferenceId(int refId) {
251: for (int i = 3; i >= 0; i--) {
252: buf[REFERENCE_ID_INDEX + i] = (byte) (refId & 0xff);
253: refId >>>= 8; // shift right one-byte
254: }
255: }
256:
257: /***
258: * Returns the reference id as defined in RFC-1305, which is
259: * a 32-bit integer whose value is dependent on several criteria.
260: *
261: * @return the reference id as defined in RFC-1305.
262: */
263: public int getReferenceId() {
264: return getInt(REFERENCE_ID_INDEX);
265: }
266:
267: /***
268: * Returns the reference id string. String cannot be null but
269: * value is dependent on the version of the NTP spec supported
270: * and stratum level. Value can be an empty string, clock type string,
271: * IP address, or a hex string.
272: *
273: * @return the reference id string.
274: */
275: public String getReferenceIdString() {
276: int version = getVersion();
277: int stratum = getStratum();
278: if (version == VERSION_3 || version == VERSION_4) {
279: if (stratum == 0 || stratum == 1) {
280: return idAsString(); // 4-character ASCII string (e.g. GPS, USNO)
281: }
282: // in NTPv4 servers this is latest transmit timestamp of ref source
283: if (version == VERSION_4)
284: return idAsHex();
285: }
286:
287: // Stratum 2 and higher this is a four-octet IPv4 address
288: // of the primary reference host.
289: if (stratum >= 2) {
290: return idAsIPAddress();
291: }
292: return idAsHex();
293: }
294:
295: /***
296: * Returns Reference id as dotted IP address.
297: * @return refId as IP address string.
298: */
299: private String idAsIPAddress() {
300: return ui(buf[REFERENCE_ID_INDEX]) + "."
301: + ui(buf[REFERENCE_ID_INDEX + 1]) + "."
302: + ui(buf[REFERENCE_ID_INDEX + 2]) + "."
303: + ui(buf[REFERENCE_ID_INDEX + 3]);
304: }
305:
306: private String idAsString() {
307: String id = "";
308: for (int i = 0; i <= 3; i++) {
309: char c = (char) buf[REFERENCE_ID_INDEX + i];
310: if (c == 0)
311: break; // 0-terminated string
312: id = id + c;
313: }
314: return id;
315: }
316:
317: private String idAsHex() {
318: return Integer.toHexString(getReferenceId());
319: }
320:
321: /***
322: * Returns the transmit timestamp as defined in RFC-1305.
323: *
324: * @return the transmit timestamp as defined in RFC-1305.
325: * Never returns a null object.
326: */
327: public TimeStamp getTransmitTimeStamp() {
328: return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
329: }
330:
331: /***
332: * Set transmit time with NTP timestamp.
333: * If <code>ts</code> is null then zero time is used.
334: *
335: * @param ts NTP timestamp
336: */
337: public void setTransmitTime(TimeStamp ts) {
338: setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
339: }
340:
341: /***
342: * Set originate timestamp given NTP TimeStamp object.
343: * If <code>ts</code> is null then zero time is used.
344: *
345: * @param ts NTP timestamp
346: */
347: public void setOriginateTimeStamp(TimeStamp ts) {
348: setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
349: }
350:
351: /***
352: * Returns the originate time as defined in RFC-1305.
353: *
354: * @return the originate time.
355: * Never returns null.
356: */
357: public TimeStamp getOriginateTimeStamp() {
358: return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
359: }
360:
361: /***
362: * Returns the reference time as defined in RFC-1305.
363: *
364: * @return the reference time as <code>TimeStamp</code> object.
365: * Never returns null.
366: */
367: public TimeStamp getReferenceTimeStamp() {
368: return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
369: }
370:
371: /***
372: * Set Reference time with NTP timestamp. If <code>ts</code> is null
373: * then zero time is used.
374: *
375: * @param ts NTP timestamp
376: */
377: public void setReferenceTime(TimeStamp ts) {
378: setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
379: }
380:
381: /***
382: * Returns receive timestamp as defined in RFC-1305.
383: *
384: * @return the receive time.
385: * Never returns null.
386: */
387: public TimeStamp getReceiveTimeStamp() {
388: return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
389: }
390:
391: /***
392: * Set receive timestamp given NTP TimeStamp object.
393: * If <code>ts</code> is null then zero time is used.
394: *
395: * @param ts timestamp
396: */
397: public void setReceiveTimeStamp(TimeStamp ts) {
398: setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
399: }
400:
401: /***
402: * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
403: * correspond to the protocol used to obtain the timing information.
404: *
405: * @return packet type string identifier which in this case is "NTP".
406: */
407: public String getType() {
408: return "NTP";
409: }
410:
411: /***
412: * @return 4 bytes as 32-bit int
413: */
414: private int getInt(int index) {
415: int i = ui(buf[index]) << 24 | ui(buf[index + 1]) << 16
416: | ui(buf[index + 2]) << 8 | ui(buf[index + 3]);
417:
418: return i;
419: }
420:
421: /***
422: * Get NTP Timestamp at specified starting index.
423: *
424: * @param index index into data array
425: * @return TimeStamp object for 64 bits starting at index
426: */
427: private TimeStamp getTimestamp(int index) {
428: return new TimeStamp(getLong(index));
429: }
430:
431: /***
432: * Get Long value represented by bits starting at specified index.
433: *
434: * @return 8 bytes as 64-bit long
435: */
436: private long getLong(int index) {
437: long i = ul(buf[index]) << 56 | ul(buf[index + 1]) << 48
438: | ul(buf[index + 2]) << 40 | ul(buf[index + 3]) << 32
439: | ul(buf[index + 4]) << 24 | ul(buf[index + 5]) << 16
440: | ul(buf[index + 6]) << 8 | ul(buf[index + 7]);
441: return i;
442: }
443:
444: /***
445: * Sets the NTP timestamp at the given array index.
446: *
447: * @param index index into the byte array.
448: * @param t TimeStamp.
449: */
450: private void setTimestamp(int index, TimeStamp t) {
451: long ntpTime = (t == null) ? 0 : t.ntpValue();
452: // copy 64-bits from Long value into 8 x 8-bit bytes of array
453: // one byte at a time shifting 8-bits for each position.
454: for (int i = 7; i >= 0; i--) {
455: buf[index + i] = (byte) (ntpTime & 0xFF);
456: ntpTime >>>= 8; // shift to next byte
457: }
458: // buf[index] |= 0x80; // only set if 1900 baseline....
459: }
460:
461: /***
462: * Returns the datagram packet with the NTP details already filled in.
463: *
464: * @return a datagram packet.
465: */
466: public DatagramPacket getDatagramPacket() {
467: if (dp == null)
468: synchronized (this ) {
469: if (dp == null) {
470: dp = new DatagramPacket(buf, buf.length);
471: dp.setPort(NTP_PORT);
472: }
473: }
474: return dp;
475: }
476:
477: /***
478: * Set the contents of this object from source datagram packet.
479: *
480: * @param srcDp source DatagramPacket to copy contents from.
481: */
482: public void setDatagramPacket(DatagramPacket srcDp) {
483: byte[] incomingBuf = srcDp.getData();
484: int len = srcDp.getLength();
485: if (len > buf.length)
486: len = buf.length;
487:
488: System.arraycopy(incomingBuf, 0, buf, 0, len);
489: }
490:
491: /***
492: * Convert byte to unsigned integer.
493: * Java only has signed types so we have to do
494: * more work to get unsigned ops.
495: *
496: * @param b
497: * @return unsigned int value of byte
498: */
499: protected final static int ui(byte b) {
500: int i = b & 0xFF;
501: return i;
502: }
503:
504: /***
505: * Convert byte to unsigned long.
506: * Java only has signed types so we have to do
507: * more work to get unsigned ops
508: *
509: * @param b
510: * @return unsigned long value of byte
511: */
512: protected final static long ul(byte b) {
513: long i = b & 0xFF;
514: return i;
515: }
516:
517: /***
518: * Returns details of NTP packet as a string.
519: *
520: * @return details of NTP packet as a string.
521: */
522: public String toString() {
523: return "[" + "version:" + getVersion() + ", mode:" + getMode()
524: + ", poll:" + getPoll() + ", precision:"
525: + getPrecision() + ", delay:" + getRootDelay()
526: + ", dispersion(ms):"
527: + getRootDispersionInMillisDouble() + ", id:"
528: + getReferenceIdString() + ", xmitTime:"
529: + getTransmitTimeStamp().toDateString() + " ]";
530: }
531:
532: }
|