1 package org.apache.commons.net.ntp;
2 /*
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 import java.net.DatagramPacket;
20
21 /***
22 * Implementation of NtpV3Packet with methods converting Java objects to/from
23 * the Network Time Protocol (NTP) data message header format described in RFC-1305.
24 *
25 * @author Naz Irizarry, MITRE Corp
26 * @author Jason Mathews, MITRE Corp
27 *
28 * @version $Revision: 1417442 $
29 */
30 public class NtpV3Impl implements NtpV3Packet
31 {
32
33 private static final int MODE_INDEX = 0;
34 private static final int MODE_SHIFT = 0;
35
36 private static final int VERSION_INDEX = 0;
37 private static final int VERSION_SHIFT = 3;
38
39 private static final int LI_INDEX = 0;
40 private static final int LI_SHIFT = 6;
41
42 private static final int STRATUM_INDEX = 1;
43 private static final int POLL_INDEX = 2;
44 private static final int PRECISION_INDEX = 3;
45
46 private static final int ROOT_DELAY_INDEX = 4;
47 private static final int ROOT_DISPERSION_INDEX = 8;
48 private static final int REFERENCE_ID_INDEX = 12;
49
50 private static final int REFERENCE_TIMESTAMP_INDEX = 16;
51 private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
52 private static final int RECEIVE_TIMESTAMP_INDEX = 32;
53 private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
54
55 // private static final int KEY_IDENTIFIER_INDEX = 48;
56 // private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */
57
58 private final byte[] buf = new byte[48];
59
60 private volatile DatagramPacket dp;
61
62 /** Creates a new instance of NtpV3Impl */
63 public NtpV3Impl()
64 {
65 }
66
67 /***
68 * Returns mode as defined in RFC-1305 which is a 3-bit integer
69 * whose value is indicated by the MODE_xxx parameters.
70 *
71 * @return mode as defined in RFC-1305.
72 */
73 @Override
74 public int getMode()
75 {
76 return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7;
77 }
78
79 /***
80 * Return human-readable name of message mode type as described in
81 * RFC 1305.
82 * @return mode name as string.
83 */
84 @Override
85 public String getModeName()
86 {
87 return NtpUtils.getModeName(getMode());
88 }
89
90 /***
91 * Set mode as defined in RFC-1305.
92 * @param mode
93 */
94 @Override
95 public void setMode(int mode)
96 {
97 buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
98 }
99
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 }