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