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: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $
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 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 // Stratum 2 and higher this is a four-octet IPv4 address
312 // of the primary reference host.
313 if (stratum >= 2) {
314 return idAsIPAddress();
315 }
316 return idAsHex();
317 }
318
319 /***
320 * Returns Reference id as dotted IP address.
321 * @return refId as IP address string.
322 */
323 private String idAsIPAddress()
324 {
325 return ui(buf[REFERENCE_ID_INDEX]) + "." +
326 ui(buf[REFERENCE_ID_INDEX + 1]) + "." +
327 ui(buf[REFERENCE_ID_INDEX + 2]) + "." +
328 ui(buf[REFERENCE_ID_INDEX + 3]);
329 }
330
331 private String idAsString()
332 {
333 StringBuilder id = new StringBuilder();
334 for (int i = 0; i <= 3; i++) {
335 char c = (char) buf[REFERENCE_ID_INDEX + i];
336 if (c == 0) break; // 0-terminated string
337 id.append(c);
338 }
339 return id.toString();
340 }
341
342 private String idAsHex()
343 {
344 return Integer.toHexString(getReferenceId());
345 }
346
347 /***
348 * Returns the transmit timestamp as defined in RFC-1305.
349 *
350 * @return the transmit timestamp as defined in RFC-1305.
351 * Never returns a null object.
352 */
353 public TimeStamp getTransmitTimeStamp()
354 {
355 return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
356 }
357
358 /***
359 * Set transmit time with NTP timestamp.
360 * If <code>ts</code> is null then zero time is used.
361 *
362 * @param ts NTP timestamp
363 */
364 public void setTransmitTime(TimeStamp ts)
365 {
366 setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
367 }
368
369 /***
370 * Set originate timestamp given NTP TimeStamp object.
371 * If <code>ts</code> is null then zero time is used.
372 *
373 * @param ts NTP timestamp
374 */
375 public void setOriginateTimeStamp(TimeStamp ts)
376 {
377 setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
378 }
379
380 /***
381 * Returns the originate time as defined in RFC-1305.
382 *
383 * @return the originate time.
384 * Never returns null.
385 */
386 public TimeStamp getOriginateTimeStamp()
387 {
388 return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
389 }
390
391 /***
392 * Returns the reference time as defined in RFC-1305.
393 *
394 * @return the reference time as <code>TimeStamp</code> object.
395 * Never returns null.
396 */
397 public TimeStamp getReferenceTimeStamp()
398 {
399 return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
400 }
401
402 /***
403 * Set Reference time with NTP timestamp. If <code>ts</code> is null
404 * then zero time is used.
405 *
406 * @param ts NTP timestamp
407 */
408 public void setReferenceTime(TimeStamp ts)
409 {
410 setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
411 }
412
413 /***
414 * Returns receive timestamp as defined in RFC-1305.
415 *
416 * @return the receive time.
417 * Never returns null.
418 */
419 public TimeStamp getReceiveTimeStamp()
420 {
421 return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
422 }
423
424 /***
425 * Set receive timestamp given NTP TimeStamp object.
426 * If <code>ts</code> is null then zero time is used.
427 *
428 * @param ts timestamp
429 */
430 public void setReceiveTimeStamp(TimeStamp ts)
431 {
432 setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
433 }
434
435 /***
436 * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...)
437 * correspond to the protocol used to obtain the timing information.
438 *
439 * @return packet type string identifier which in this case is "NTP".
440 */
441 public String getType()
442 {
443 return "NTP";
444 }
445
446 /***
447 * @return 4 bytes as 32-bit int
448 */
449 private int getInt(int index)
450 {
451 int i = ui(buf[index]) << 24 |
452 ui(buf[index + 1]) << 16 |
453 ui(buf[index + 2]) << 8 |
454 ui(buf[index + 3]);
455
456 return i;
457 }
458
459 /***
460 * Get NTP Timestamp at specified starting index.
461 *
462 * @param index index into data array
463 * @return TimeStamp object for 64 bits starting at index
464 */
465 private TimeStamp getTimestamp(int index)
466 {
467 return new TimeStamp(getLong(index));
468 }
469
470 /***
471 * Get Long value represented by bits starting at specified index.
472 *
473 * @return 8 bytes as 64-bit long
474 */
475 private long getLong(int index)
476 {
477 long i = ul(buf[index]) << 56 |
478 ul(buf[index + 1]) << 48 |
479 ul(buf[index + 2]) << 40 |
480 ul(buf[index + 3]) << 32 |
481 ul(buf[index + 4]) << 24 |
482 ul(buf[index + 5]) << 16 |
483 ul(buf[index + 6]) << 8 |
484 ul(buf[index + 7]);
485 return i;
486 }
487
488 /***
489 * Sets the NTP timestamp at the given array index.
490 *
491 * @param index index into the byte array.
492 * @param t TimeStamp.
493 */
494 private void setTimestamp(int index, TimeStamp t)
495 {
496 long ntpTime = (t == null) ? 0 : t.ntpValue();
497 // copy 64-bits from Long value into 8 x 8-bit bytes of array
498 // one byte at a time shifting 8-bits for each position.
499 for (int i = 7; i >= 0; i--) {
500 buf[index + i] = (byte) (ntpTime & 0xFF);
501 ntpTime >>>= 8; // shift to next byte
502 }
503 // buf[index] |= 0x80; // only set if 1900 baseline....
504 }
505
506 /***
507 * Returns the datagram packet with the NTP details already filled in.
508 *
509 * @return a datagram packet.
510 */
511 public synchronized DatagramPacket getDatagramPacket()
512 {
513 if (dp == null) {
514 dp = new DatagramPacket(buf, buf.length);
515 dp.setPort(NTP_PORT);
516 }
517 return dp;
518 }
519
520 /***
521 * Set the contents of this object from source datagram packet.
522 *
523 * @param srcDp source DatagramPacket to copy contents from.
524 */
525 public void setDatagramPacket(DatagramPacket srcDp)
526 {
527 byte[] incomingBuf = srcDp.getData();
528 int len = srcDp.getLength();
529 if (len > buf.length)
530 len = buf.length;
531
532 System.arraycopy(incomingBuf, 0, buf, 0, len);
533 }
534
535 /***
536 * Convert byte to unsigned integer.
537 * Java only has signed types so we have to do
538 * more work to get unsigned ops.
539 *
540 * @param b
541 * @return unsigned int value of byte
542 */
543 protected final static int ui(byte b)
544 {
545 int i = b & 0xFF;
546 return i;
547 }
548
549 /***
550 * Convert byte to unsigned long.
551 * Java only has signed types so we have to do
552 * more work to get unsigned ops
553 *
554 * @param b
555 * @return unsigned long value of byte
556 */
557 protected final static long ul(byte b)
558 {
559 long i = b & 0xFF;
560 return i;
561 }
562
563 /***
564 * Returns details of NTP packet as a string.
565 *
566 * @return details of NTP packet as a string.
567 */
568 @Override
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 }