Exemplo n.º 1
0
  private void compute(NtpPacket packet, long t4) {
    Timestamp time1 = packet.getOriginateTime();
    long t1 = time1.timeInMillisValue();

    // Receive Time is time request received by server (t2)
    Timestamp time2 = packet.getReceiveTime();
    long t2 = time2.timeInMillisValue();

    // Transmit time is time reply sent by server (t3)
    Timestamp time3 = packet.getTransmitTime();
    long t3 = time3.timeInMillisValue();

    delayIsSet = false;
    offsetIsSet = false;

    /*
     * Round-trip network delay and local clock offset (or time drift) is
     * calculated according to this standard NTP equation:
     *
     * LocalClockOffset = ((ReceiveTimestamp - OriginateTimestamp) +
     * (TransmitTimestamp - DestinationTimestamp)) / 2
     *
     * equations from RFC-1305 (NTPv3) roundtrip delay = (t4 - t1) - (t3 -
     * t2) local clock offset = ((t2 - t1) + (t3 - t4)) / 2
     *
     * It takes into account network delays and assumes that they are
     * symmetrical.
     *
     * Note the typo in SNTP RFCs 1769/2030 which state that the delay is
     * (T4 - T1) - (T2 - T3) with the "T2" and "T3" switched.
     */
    if (time1.ntpValue() == 0) {
      // without originate time cannot determine when packet went out
      // might be via a broadcast NTP packet...
      if (time3.ntpValue() != 0) {
        offset = t3 - t4;
        offsetIsSet = true;
      }
      // else, ERROR: cannot compute delay/offset
    } else if ((time2.ntpValue() == 0) || (time3.ntpValue() == 0)) {

      if (t4 < t1) {
        throw new AssertionError("return-time < originate-time");
      }

      // without receive or xmit time cannot figure out processing
      // time
      // so delay is simply the network travel time
      delay = t4 - t1;
      delayIsSet = true;

      // TODO: is offset still valid if rcvNtpTime=0 || xmitNtpTime=0 ???
      // Could always hash origNtpTime (sendTime) but if host doesn't set
      // it
      // then it's an malformed ntp host anyway and we don't care?
      // If server is in broadcast mode then we never send out a query in
      // first place...
      if (time2.ntpValue() != 0) {
        // xmitTime is 0 just use rcv time
        offset = t2 - t1;
      } else if (time3.ntpValue() != 0) {
        // rcvTime is 0 just use xmitTime time
        offset = t3 - t4;
      }

      offsetIsSet = true;
    } else {
      // assert xmitTime >= rcvTime: difference typically < 1ms
      if (t3 < t2) {
        throw new AssertionError("malformed NTP packet, transmit-time < receive-time");
      }

      // assert returnTime >= origTime: network delay could not be
      // negative
      if (t4 < t1) {
        throw new AssertionError("return-time < originate-time");
      }

      long troundtrip = t4 - t1;

      // subtract processing time from round-trip network delay
      long tprocessing = t3 - t2;

      // in normal cases the processing delta is less than
      // the total roundtrip network travel time.
      if (tprocessing <= troundtrip) {
        troundtrip -= tprocessing; // delay = (t4 - t1) - (t3 - t2)
      } else {
        // if delta - delayValue == 1 ms then it's a round-off error
        // e.g. delay=3ms, processing=4ms
        if (tprocessing - troundtrip == 1) {
          // delayValue == 0 -> local clock saw no tick change but
          // destination clock did
          if (troundtrip != 0) {
            troundtrip = 0;
          }
        }
      }

      offset = ((t2 - t1) + (t3 - t4) - troundtrip) / 2;

      delayIsSet = true;
      offsetIsSet = true;
    }
  }