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