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