View Javadoc

    1   package org.apache.commons.net.ntp;
    2   /*
    3    * Copyright 2001-2005 The Apache Software Foundation
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License");
    6    * you may not use this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  import java.util.List;
    19  import java.util.ArrayList;
    20
    21  /***
    22   * Wrapper class to network time packet messages (NTP, etc) that computes
    23   * related timing info and stats.
    24   *
    25   * @author Jason Mathews, MITRE Corp
    26   *
    27   * @version $Revision: 165675 $ $Date: 2005-05-02 21:09:55 +0100 (Mon, 02 May 2005) $
    28   */
    29  public class TimeInfo {
    30
    31      private NtpV3Packet _message;
    32      private List _comments;
    33      private Long _delay;
    34      private Long _offset;
    35
    36      /***
    37       * time at which time message packet was received by local machine
    38       */
    39      private long _returnTime;
    40
    41      /***
    42       * flag indicating that the TimeInfo details was processed and delay/offset were computed
    43       */
    44      private boolean _detailsComputed;
    45
    46      /***
    47       * Create TimeInfo object with raw packet message and destination time received.
    48       *
    49       * @param message NTP message packet
    50       * @param returnTime  destination receive time
    51       * @throws IllegalArgumentException if message is null
    52       */
    53      public TimeInfo(NtpV3Packet message, long returnTime) {
    54          this(message, returnTime, null, true);
    55      }
    56
    57      /***
    58       * Create TimeInfo object with raw packet message and destination time received.
    59       *
    60       * @param message NTP message packet
    61       * @param returnTime  destination receive time
    62       * @param comments List of errors/warnings identified during processing
    63       * @throws IllegalArgumentException if message is null
    64       */
    65      public TimeInfo(NtpV3Packet message, long returnTime, List comments)
    66      {
    67              this(message, returnTime, comments, true);
    68      }
    69
    70      /***
    71       * Create TimeInfo object with raw packet message and destination time received.
    72       * Auto-computes details if computeDetails flag set otherwise this is delayed
    73       * until computeDetails() is called. Delayed computation is for fast
    74       * intialization when sub-millisecond timing is needed.
    75       *
    76       * @param msgPacket NTP message packet
    77       * @param returnTime  destination receive time
    78       * @param doComputeDetails  flag to pre-compute delay/offset values
    79       * @throws IllegalArgumentException if message is null
    80       */
    81      public TimeInfo(NtpV3Packet msgPacket, long returnTime, boolean doComputeDetails)
    82      {
    83              this(msgPacket, returnTime, null, doComputeDetails);
    84      }
    85
    86      /***
    87       * Create TimeInfo object with raw packet message and destination time received.
    88       * Auto-computes details if computeDetails flag set otherwise this is delayed
    89       * until computeDetails() is called. Delayed computation is for fast
    90       * intialization when sub-millisecond timing is needed.
    91       *
    92       * @param message NTP message packet
    93       * @param returnTime  destination receive time
    94       * @param comments  list of comments used to store errors/warnings with message
    95       * @param doComputeDetails  flag to pre-compute delay/offset values
    96       * @throws IllegalArgumentException if message is null
    97       */
    98      public TimeInfo(NtpV3Packet message, long returnTime, List comments,
    99                     boolean doComputeDetails)
    100     {
    101         if (message == null)
    102             throw new IllegalArgumentException("message cannot be null");
    103         this._returnTime = returnTime;
    104         this._message = message;
    105         this._comments = comments;
    106         if (doComputeDetails)
    107             computeDetails();
    108     }
    109
    110     /***
    111      * Add comment (error/warning) to list of comments associated
    112      * with processing of NTP parameters. If comment list not create
    113      * then one will be created.
    114      *
    115      * @param comment
    116      */
    117     public void addComment(String comment)
    118     {
    119         if (_comments == null) {
    120             _comments = new ArrayList();
    121         }
    122         _comments.add(comment);
    123     }
    124
    125     /***
    126      * Compute and validate details of the NTP message packet. Computed
    127      * fields include the offset and delay.
    128      */
    129     public void computeDetails()
    130     {
    131         if (_detailsComputed) {
    132             return; // details already computed - do nothing
    133         }
    134         _detailsComputed = true;
    135         if (_comments == null) {
    136             _comments = new ArrayList();
    137         }
    138
    139         TimeStamp origNtpTime = _message.getOriginateTimeStamp();
    140         long origTime = origNtpTime.getTime();
    141
    142         // Receive Time is time request received by server (t2)
    143         TimeStamp rcvNtpTime = _message.getReceiveTimeStamp();
    144         long rcvTime = rcvNtpTime.getTime();
    145
    146         // Transmit time is time reply sent by server (t3)
    147         TimeStamp xmitNtpTime = _message.getTransmitTimeStamp();
    148         long xmitTime = xmitNtpTime.getTime();
    149
    150         /*
    151          * Round-trip network delay and local clock offset (or time drift) is calculated
    152          * according to this standard NTP equation:
    153          *
    154          * LocalClockOffset = ((ReceiveTimestamp - OriginateTimestamp) +
    155          *		        (TransmitTimestamp - DestinationTimestamp)) / 2
    156          *
    157          * equations from RFC-1305 (NTPv3)
    158          *      roundtrip delay = (t4 - t1) - (t3 - t2)
    159          *      local clock offset = ((t2 - t1) + (t3 - t4)) / 2
    160          *
    161          * It takes into account network delays and assumes that they are symmetrical.
    162          *
    163          * Note the typo in SNTP RFCs 1769/2030 which state that the delay
    164          * is (T4 - T1) - (T2 - T3) with the "T2" and "T3" switched.
    165          */
    166         if (origNtpTime.ntpValue() == 0)
    167         {
    168             // without originate time cannot determine when packet went out
    169             // might be via a broadcast NTP packet...
    170             if (xmitNtpTime.ntpValue() != 0)
    171             {
    172                 _offset = new Long(xmitTime - _returnTime);
    173                 _comments.add("Error: zero orig time -- cannot compute delay");
    174             } else
    175                 _comments.add("Error: zero orig time -- cannot compute delay/offset");
    176         } else if (rcvNtpTime.ntpValue() == 0 || xmitNtpTime.ntpValue() == 0)
    177         {
    178             _comments.add("Warning: zero rcvNtpTime or xmitNtpTime");
    179             // assert destTime >= origTime since network delay cannot be negative
    180             if (origTime > _returnTime)
    181                 _comments.add("Error: OrigTime > DestRcvTime");
    182             else
    183             {
    184                 // without receive or xmit time cannot figure out processing time
    185                 // so delay is simply the network travel time
    186                 _delay = new Long(_returnTime - origTime);
    187             }
    188             // TODO: is offset still valid if rcvNtpTime=0 || xmitNtpTime=0 ???
    189             // Could always hash origNtpTime (sendTime) but if host doesn't set it
    190             // then it's an malformed ntp host anyway and we don't care?
    191             // If server is in broadcast mode then we never send out a query in first place...
    192             if (rcvNtpTime.ntpValue() != 0)
    193             {
    194                 // xmitTime is 0 just use rcv time
    195                 _offset = new Long(rcvTime - origTime);
    196             } else if (xmitNtpTime.ntpValue() != 0)
    197             {
    198                 // rcvTime is 0 just use xmitTime time
    199                 _offset = new Long(xmitTime - _returnTime);
    200             }
    201         } else
    202         {
    203              long delayValue = _returnTime - origTime;
    204              // assert xmitTime >= rcvTime: difference typically < 1ms
    205              if (xmitTime < rcvTime)
    206              {
    207                  // server cannot send out a packet before receiving it...
    208                  _comments.add("Error: xmitTime < rcvTime"); // time-travel not allowed
    209              } else
    210              {
    211                  // subtract processing time from round-trip network delay
    212                  long delta = xmitTime - rcvTime;
    213                  // in normal cases the processing delta is less than
    214                  // the total roundtrip network travel time.
    215                  if (delta <= delayValue)
    216                  {
    217                      delayValue -= delta; // delay = (t4 - t1) - (t3 - t2)
    218                  } else
    219                  {
    220                      // if delta - delayValue == 1 ms then it's a round-off error
    221                      // e.g. delay=3ms, processing=4ms
    222                      if (delta - delayValue == 1)
    223                      {
    224                          // delayValue == 0 -> local clock saw no tick change but destination clock did
    225                          if (delayValue != 0)
    226                          {
    227                              _comments.add("Info: processing time > total network time by 1 ms -> assume zero delay");
    228                              delayValue = 0;
    229                          }
    230                      } else
    231                          _comments.add("Warning: processing time > total network time");
    232                  }
    233              }
    234              _delay = new Long(delayValue);
    235             if (origTime > _returnTime) // assert destTime >= origTime
    236                 _comments.add("Error: OrigTime > DestRcvTime");
    237
    238             _offset = new Long(((rcvTime - origTime) + (xmitTime - _returnTime)) / 2);
    239         }
    240     }
    241
    242     /***
    243      * Return list of comments (if any) during processing of NTP packet.
    244      *
    245      * @return List or null if not yet computed
    246      */
    247     public List getComments()
    248     {
    249         return _comments;
    250     }
    251
    252     /***
    253      * Get round-trip network delay. If null then could not compute the delay.
    254      *
    255      * @return Long or null if delay not available.
    256      */
    257     public Long getDelay()
    258     {
    259         return _delay;
    260     }
    261
    262     /***
    263      * Get clock offset needed to adjust local clock to match remote clock. If null then could not
    264      * compute the offset.
    265      *
    266      * @return Long or null if offset not available.
    267      */
    268     public Long getOffset()
    269     {
    270         return _offset;
    271     }
    272
    273     /***
    274      * Returns NTP message packet.
    275      *
    276      * @return NTP message packet.
    277      */
    278     public NtpV3Packet getMessage()
    279     {
    280         return _message;
    281     }
    282
    283     /***
    284      * Returns time at which time message packet was received by local machine.
    285      *
    286      * @return packet return time.
    287      */
    288     public long getReturnTime()
    289     {
    290         return _returnTime;
    291     }
    292
    293 }