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