1 package org.apache.commons.net.ntp;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 15:09:55 -0500 (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;
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;
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();
303 }
304
305 if (version == VERSION_4)
306 return idAsHex();
307 }
308
309
310
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;
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
496
497 for (int i = 7; i >= 0; i--) {
498 buf[index + i] = (byte) (ntpTime & 0xFF);
499 ntpTime >>>= 8;
500 }
501
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 }