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