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