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