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