This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-net.git
The following commit(s) were added to refs/heads/master by this push: new 61fe4b52 Move Apache license header to the top of the file 61fe4b52 is described below commit 61fe4b5277b39cfa8f438223956040a3a928b222 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Tue Aug 30 10:49:57 2022 -0400 Move Apache license header to the top of the file --- .../apache/commons/net/examples/ntp/NTPClient.java | 361 ++--- .../commons/net/examples/ntp/TimeClient.java | 202 +-- .../apache/commons/net/ftp/FTPListParseEngine.java | 37 +- .../org/apache/commons/net/ntp/NTPUDPClient.java | 288 ++-- .../java/org/apache/commons/net/ntp/NtpUtils.java | 230 ++-- .../java/org/apache/commons/net/ntp/NtpV3Impl.java | 1397 ++++++++++---------- .../org/apache/commons/net/ntp/NtpV3Packet.java | 518 ++++---- .../java/org/apache/commons/net/ntp/TimeInfo.java | 686 +++++----- .../java/org/apache/commons/net/ntp/TimeStamp.java | 3 +- .../commons/net/time/TimeTestSimpleServer.java | 320 ++--- 10 files changed, 2029 insertions(+), 2013 deletions(-) diff --git a/src/main/java/org/apache/commons/net/examples/ntp/NTPClient.java b/src/main/java/org/apache/commons/net/examples/ntp/NTPClient.java index 1f067f7a..8b2ff648 100644 --- a/src/main/java/org/apache/commons/net/examples/ntp/NTPClient.java +++ b/src/main/java/org/apache/commons/net/examples/ntp/NTPClient.java @@ -1,180 +1,181 @@ -package org.apache.commons.net.examples.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.io.IOException; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.text.NumberFormat; - -import org.apache.commons.net.ntp.NTPUDPClient; -import org.apache.commons.net.ntp.NtpUtils; -import org.apache.commons.net.ntp.NtpV3Packet; -import org.apache.commons.net.ntp.TimeInfo; -import org.apache.commons.net.ntp.TimeStamp; - -/** - * This is an example program demonstrating how to use the NTPUDPClient - * class. This program sends a Datagram client request packet to a - * Network time Protocol (NTP) service port on a specified server, - * retrieves the time, and prints it to standard output along with - * the fields from the NTP message header (e.g. stratum level, reference id, - * poll interval, root delay, mode, ...) - * See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> - * for details. - * <p> - * Usage: NTPClient <hostname-or-address-list> - * <br> - * Example: NTPClient clock.psu.edu - * - */ -public final class NTPClient -{ - - private static final NumberFormat numberFormat = new java.text.DecimalFormat("0.00"); - - public static void main(final String[] args) - { - if (args.length == 0) { - System.err.println("Usage: NTPClient <hostname-or-address-list>"); - System.exit(1); - } - - final NTPUDPClient client = new NTPUDPClient(); - // We want to timeout if a response takes longer than 10 seconds - client.setDefaultTimeout(10000); - try { - client.open(); - for (final String arg : args) - { - System.out.println(); - try { - final InetAddress hostAddr = InetAddress.getByName(arg); - System.out.println("> " + hostAddr.getHostName() + "/" + hostAddr.getHostAddress()); - final TimeInfo info = client.getTime(hostAddr); - processResponse(info); - } catch (final IOException ioe) { - ioe.printStackTrace(); - } - } - } catch (final SocketException e) { - e.printStackTrace(); - } - - client.close(); - } - - /** - * Process <code>TimeInfo</code> object and print its details. - * @param info <code>TimeInfo</code> object. - */ - public static void processResponse(final TimeInfo info) - { - final NtpV3Packet message = info.getMessage(); - final int stratum = message.getStratum(); - final String refType; - if (stratum <= 0) { - refType = "(Unspecified or Unavailable)"; - } else if (stratum == 1) { - refType = "(Primary Reference; e.g., GPS)"; // GPS, radio clock, etc. - } else { - refType = "(Secondary Reference; e.g. via NTP or SNTP)"; - } - // stratum should be 0..15... - System.out.println(" Stratum: " + stratum + " " + refType); - final int version = message.getVersion(); - final int li = message.getLeapIndicator(); - System.out.println(" leap=" + li + ", version=" - + version + ", precision=" + message.getPrecision()); - - System.out.println(" mode: " + message.getModeName() + " (" + message.getMode() + ")"); - final int poll = message.getPoll(); - // poll value typically btwn MINPOLL (4) and MAXPOLL (14) - System.out.println(" poll: " + (poll <= 0 ? 1 : (int) Math.pow(2, poll)) - + " seconds" + " (2 ** " + poll + ")"); - final double disp = message.getRootDispersionInMillisDouble(); - System.out.println(" rootdelay=" + numberFormat.format(message.getRootDelayInMillisDouble()) - + ", rootdispersion(ms): " + numberFormat.format(disp)); - - final int refId = message.getReferenceId(); - String refAddr = NtpUtils.getHostAddress(refId); - String refName = null; - if (refId != 0) { - if (refAddr.equals("127.127.1.0")) { - refName = "LOCAL"; // This is the ref address for the Local Clock - } else if (stratum >= 2) { - // If reference id has 127.127 prefix then it uses its own reference clock - // defined in the form 127.127.clock-type.unit-num (e.g. 127.127.8.0 mode 5 - // for GENERIC DCF77 AM; see refclock.htm from the NTP software distribution. - if (!refAddr.startsWith("127.127")) { - try { - final InetAddress addr = InetAddress.getByName(refAddr); - final String name = addr.getHostName(); - if (name != null && !name.equals(refAddr)) { - refName = name; - } - } catch (final UnknownHostException e) { - // some stratum-2 servers sync to ref clock device but fudge stratum level higher... (e.g. 2) - // ref not valid host maybe it's a reference clock name? - // otherwise just show the ref IP address. - refName = NtpUtils.getReferenceClock(message); - } - } - } else if (version >= 3 && (stratum == 0 || stratum == 1)) { - refName = NtpUtils.getReferenceClock(message); - // refname usually have at least 3 characters (e.g. GPS, WWV, LCL, etc.) - } - // otherwise give up on naming the beast... - } - if (refName != null && refName.length() > 1) { - refAddr += " (" + refName + ")"; - } - System.out.println(" Reference Identifier:\t" + refAddr); - - final TimeStamp refNtpTime = message.getReferenceTimeStamp(); - System.out.println(" Reference Timestamp:\t" + refNtpTime + " " + refNtpTime.toDateString()); - - // Originate Time is time request sent by client (t1) - final TimeStamp origNtpTime = message.getOriginateTimeStamp(); - System.out.println(" Originate Timestamp:\t" + origNtpTime + " " + origNtpTime.toDateString()); - - final long destTimeMillis = info.getReturnTime(); - // Receive Time is time request received by server (t2) - final TimeStamp rcvNtpTime = message.getReceiveTimeStamp(); - System.out.println(" Receive Timestamp:\t" + rcvNtpTime + " " + rcvNtpTime.toDateString()); - - // Transmit time is time reply sent by server (t3) - final TimeStamp xmitNtpTime = message.getTransmitTimeStamp(); - System.out.println(" Transmit Timestamp:\t" + xmitNtpTime + " " + xmitNtpTime.toDateString()); - - // Destination time is time reply received by client (t4) - final TimeStamp destNtpTime = TimeStamp.getNtpTime(destTimeMillis); - System.out.println(" Destination Timestamp:\t" + destNtpTime + " " + destNtpTime.toDateString()); - - info.computeDetails(); // compute offset/delay if not already done - final Long offsetMillis = info.getOffset(); - final Long delayMillis = info.getDelay(); - final String delay = delayMillis == null ? "N/A" : delayMillis.toString(); - final String offset = offsetMillis == null ? "N/A" : offsetMillis.toString(); - - System.out.println(" Roundtrip delay(ms)=" + delay - + ", clock offset(ms)=" + offset); // offset in ms - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.examples.ntp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.text.NumberFormat; + +import org.apache.commons.net.ntp.NTPUDPClient; +import org.apache.commons.net.ntp.NtpUtils; +import org.apache.commons.net.ntp.NtpV3Packet; +import org.apache.commons.net.ntp.TimeInfo; +import org.apache.commons.net.ntp.TimeStamp; + +/** + * This is an example program demonstrating how to use the NTPUDPClient + * class. This program sends a Datagram client request packet to a + * Network time Protocol (NTP) service port on a specified server, + * retrieves the time, and prints it to standard output along with + * the fields from the NTP message header (e.g. stratum level, reference id, + * poll interval, root delay, mode, ...) + * See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> + * for details. + * <p> + * Usage: NTPClient <hostname-or-address-list> + * </p> + * <p> + * Example: NTPClient clock.psu.edu + * </p> + */ +public final class NTPClient +{ + + private static final NumberFormat numberFormat = new java.text.DecimalFormat("0.00"); + + public static void main(final String[] args) + { + if (args.length == 0) { + System.err.println("Usage: NTPClient <hostname-or-address-list>"); + System.exit(1); + } + + final NTPUDPClient client = new NTPUDPClient(); + // We want to timeout if a response takes longer than 10 seconds + client.setDefaultTimeout(10000); + try { + client.open(); + for (final String arg : args) + { + System.out.println(); + try { + final InetAddress hostAddr = InetAddress.getByName(arg); + System.out.println("> " + hostAddr.getHostName() + "/" + hostAddr.getHostAddress()); + final TimeInfo info = client.getTime(hostAddr); + processResponse(info); + } catch (final IOException ioe) { + ioe.printStackTrace(); + } + } + } catch (final SocketException e) { + e.printStackTrace(); + } + + client.close(); + } + + /** + * Process <code>TimeInfo</code> object and print its details. + * @param info <code>TimeInfo</code> object. + */ + public static void processResponse(final TimeInfo info) + { + final NtpV3Packet message = info.getMessage(); + final int stratum = message.getStratum(); + final String refType; + if (stratum <= 0) { + refType = "(Unspecified or Unavailable)"; + } else if (stratum == 1) { + refType = "(Primary Reference; e.g., GPS)"; // GPS, radio clock, etc. + } else { + refType = "(Secondary Reference; e.g. via NTP or SNTP)"; + } + // stratum should be 0..15... + System.out.println(" Stratum: " + stratum + " " + refType); + final int version = message.getVersion(); + final int li = message.getLeapIndicator(); + System.out.println(" leap=" + li + ", version=" + + version + ", precision=" + message.getPrecision()); + + System.out.println(" mode: " + message.getModeName() + " (" + message.getMode() + ")"); + final int poll = message.getPoll(); + // poll value typically btwn MINPOLL (4) and MAXPOLL (14) + System.out.println(" poll: " + (poll <= 0 ? 1 : (int) Math.pow(2, poll)) + + " seconds" + " (2 ** " + poll + ")"); + final double disp = message.getRootDispersionInMillisDouble(); + System.out.println(" rootdelay=" + numberFormat.format(message.getRootDelayInMillisDouble()) + + ", rootdispersion(ms): " + numberFormat.format(disp)); + + final int refId = message.getReferenceId(); + String refAddr = NtpUtils.getHostAddress(refId); + String refName = null; + if (refId != 0) { + if (refAddr.equals("127.127.1.0")) { + refName = "LOCAL"; // This is the ref address for the Local Clock + } else if (stratum >= 2) { + // If reference id has 127.127 prefix then it uses its own reference clock + // defined in the form 127.127.clock-type.unit-num (e.g. 127.127.8.0 mode 5 + // for GENERIC DCF77 AM; see refclock.htm from the NTP software distribution. + if (!refAddr.startsWith("127.127")) { + try { + final InetAddress addr = InetAddress.getByName(refAddr); + final String name = addr.getHostName(); + if (name != null && !name.equals(refAddr)) { + refName = name; + } + } catch (final UnknownHostException e) { + // some stratum-2 servers sync to ref clock device but fudge stratum level higher... (e.g. 2) + // ref not valid host maybe it's a reference clock name? + // otherwise just show the ref IP address. + refName = NtpUtils.getReferenceClock(message); + } + } + } else if (version >= 3 && (stratum == 0 || stratum == 1)) { + refName = NtpUtils.getReferenceClock(message); + // refname usually have at least 3 characters (e.g. GPS, WWV, LCL, etc.) + } + // otherwise give up on naming the beast... + } + if (refName != null && refName.length() > 1) { + refAddr += " (" + refName + ")"; + } + System.out.println(" Reference Identifier:\t" + refAddr); + + final TimeStamp refNtpTime = message.getReferenceTimeStamp(); + System.out.println(" Reference Timestamp:\t" + refNtpTime + " " + refNtpTime.toDateString()); + + // Originate Time is time request sent by client (t1) + final TimeStamp origNtpTime = message.getOriginateTimeStamp(); + System.out.println(" Originate Timestamp:\t" + origNtpTime + " " + origNtpTime.toDateString()); + + final long destTimeMillis = info.getReturnTime(); + // Receive Time is time request received by server (t2) + final TimeStamp rcvNtpTime = message.getReceiveTimeStamp(); + System.out.println(" Receive Timestamp:\t" + rcvNtpTime + " " + rcvNtpTime.toDateString()); + + // Transmit time is time reply sent by server (t3) + final TimeStamp xmitNtpTime = message.getTransmitTimeStamp(); + System.out.println(" Transmit Timestamp:\t" + xmitNtpTime + " " + xmitNtpTime.toDateString()); + + // Destination time is time reply received by client (t4) + final TimeStamp destNtpTime = TimeStamp.getNtpTime(destTimeMillis); + System.out.println(" Destination Timestamp:\t" + destNtpTime + " " + destNtpTime.toDateString()); + + info.computeDetails(); // compute offset/delay if not already done + final Long offsetMillis = info.getOffset(); + final Long delayMillis = info.getDelay(); + final String delay = delayMillis == null ? "N/A" : delayMillis.toString(); + final String offset = offsetMillis == null ? "N/A" : offsetMillis.toString(); + + System.out.println(" Roundtrip delay(ms)=" + delay + + ", clock offset(ms)=" + offset); // offset in ms + } + +} diff --git a/src/main/java/org/apache/commons/net/examples/ntp/TimeClient.java b/src/main/java/org/apache/commons/net/examples/ntp/TimeClient.java index 967b0d7a..cfd49375 100644 --- a/src/main/java/org/apache/commons/net/examples/ntp/TimeClient.java +++ b/src/main/java/org/apache/commons/net/examples/ntp/TimeClient.java @@ -1,101 +1,101 @@ -package org.apache.commons.net.examples.ntp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.io.IOException; -import java.net.InetAddress; - -import org.apache.commons.net.time.TimeTCPClient; -import org.apache.commons.net.time.TimeUDPClient; - -/** - * This is an example program demonstrating how to use the TimeTCPClient - * and TimeUDPClient classes. - * This program connects to the default time service port of a - * specified server, retrieves the time, and prints it to standard output. - * See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> - * for details. The default is to use the TCP port. Use the -udp flag to - * use the UDP port. - * <p> - * Usage: TimeClient [-udp] <hostname> - */ -public final class TimeClient -{ - - public static void main(final String[] args) - { - - if (args.length == 1) - { - try - { - timeTCP(args[0]); - } - catch (final IOException e) - { - e.printStackTrace(); - System.exit(1); - } - } - else if (args.length == 2 && args[0].equals("-udp")) - { - try - { - timeUDP(args[1]); - } - catch (final IOException e) - { - e.printStackTrace(); - System.exit(1); - } - } - else - { - System.err.println("Usage: TimeClient [-udp] <hostname>"); - System.exit(1); - } - - } - - public static void timeTCP(final String host) throws IOException - { - final TimeTCPClient client = new TimeTCPClient(); - try { - // We want to timeout if a response takes longer than 60 seconds - client.setDefaultTimeout(60000); - client.connect(host); - System.out.println(client.getDate()); - } finally { - client.disconnect(); - } - } - - public static void timeUDP(final String host) throws IOException - { - final TimeUDPClient client = new TimeUDPClient(); - - // We want to timeout if a response takes longer than 60 seconds - client.setDefaultTimeout(60000); - client.open(); - System.out.println(client.getDate(InetAddress.getByName(host))); - client.close(); - } - -} - +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.examples.ntp; + +import java.io.IOException; +import java.net.InetAddress; + +import org.apache.commons.net.time.TimeTCPClient; +import org.apache.commons.net.time.TimeUDPClient; + +/** + * This is an example program demonstrating how to use the TimeTCPClient + * and TimeUDPClient classes. + * This program connects to the default time service port of a + * specified server, retrieves the time, and prints it to standard output. + * See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> + * for details. The default is to use the TCP port. Use the -udp flag to + * use the UDP port. + * <p> + * Usage: TimeClient [-udp] <hostname> + * </p> + */ +public final class TimeClient +{ + + public static void main(final String[] args) + { + + if (args.length == 1) + { + try + { + timeTCP(args[0]); + } + catch (final IOException e) + { + e.printStackTrace(); + System.exit(1); + } + } + else if (args.length == 2 && args[0].equals("-udp")) + { + try + { + timeUDP(args[1]); + } + catch (final IOException e) + { + e.printStackTrace(); + System.exit(1); + } + } + else + { + System.err.println("Usage: TimeClient [-udp] <hostname>"); + System.exit(1); + } + + } + + public static void timeTCP(final String host) throws IOException + { + final TimeTCPClient client = new TimeTCPClient(); + try { + // We want to timeout if a response takes longer than 60 seconds + client.setDefaultTimeout(60000); + client.connect(host); + System.out.println(client.getDate()); + } finally { + client.disconnect(); + } + } + + public static void timeUDP(final String host) throws IOException + { + final TimeUDPClient client = new TimeUDPClient(); + + // We want to timeout if a response takes longer than 60 seconds + client.setDefaultTimeout(60000); + client.open(); + System.out.println(client.getDate(InetAddress.getByName(host))); + client.close(); + } + +} + diff --git a/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java b/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java index bb1189d5..bfaa7f1b 100644 --- a/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java +++ b/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.stream.Collectors; import org.apache.commons.net.util.Charsets; @@ -139,18 +140,32 @@ public class FTPListParseEngine { public FTPFile[] getFiles(final FTPFileFilter filter) throws IOException // TODO remove; not actually thrown { - final List<FTPFile> tmpResults = new ArrayList<>(); - for (final String entry : entries) { - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - if (filter.accept(temp)) { - tmpResults.add(temp); - } - } - return tmpResults.toArray(EMPTY_FTP_FILE_ARRAY); + return getFileList(filter).toArray(EMPTY_FTP_FILE_ARRAY); + } + /** + * Returns a list of FTPFile objects containing the whole list of + * files returned by the server as read by this object's parser. + * The files are filtered before being added to the array. + * + * @param filter FTPFileFilter, must not be <code>null</code>. + * + * @return a list of FTPFile objects containing the whole list of + * files returned by the server as read by this object's parser. + * <p><b> + * NOTE:</b> This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it, or use the + * a filter such as {@link FTPFileFilters#NON_NULL} which does not + * allow null entries. + * @since 3.9.0 + */ + public List<FTPFile> getFileList(final FTPFileFilter filter) + { + return entries.stream().map(e -> { + final FTPFile file = parser.parseFTPEntry(e); + return file == null && saveUnparseableEntries ? new FTPFile(e) : file; + }).filter(file -> filter.accept(file)).collect(Collectors.toList()); } /** diff --git a/src/main/java/org/apache/commons/net/ntp/NTPUDPClient.java b/src/main/java/org/apache/commons/net/ntp/NTPUDPClient.java index cb0d465d..5939a4ca 100644 --- a/src/main/java/org/apache/commons/net/ntp/NTPUDPClient.java +++ b/src/main/java/org/apache/commons/net/ntp/NTPUDPClient.java @@ -1,144 +1,144 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; - -import org.apache.commons.net.DatagramSocketClient; - -/** - * The NTPUDPClient class is a UDP implementation of a client for the - * Network Time Protocol (NTP) described in RFC 1305 as well as the - * Simple Network Time Protocol (SNTP) in RFC-2030. To use the class, - * merely open a local datagram socket with <a href="#open"> open </a> - * and call <a href="#getTime"> getTime </a> to retrieve the time. Then call - * <a href="org.apache.commons.net.DatagramSocketClient.html#close"> close </a> - * to close the connection properly. - * Successive calls to <a href="#getTime"> getTime </a> are permitted - * without re-establishing a connection. That is because UDP is a - * connectionless protocol and the Network Time Protocol is stateless. - * - */ - -public final class NTPUDPClient extends DatagramSocketClient -{ - /** The default NTP port. It is set to 123 according to RFC 1305. */ - public static final int DEFAULT_PORT = 123; - - private int version = NtpV3Packet.VERSION_3; - - /** - * Retrieves the time information from the specified server on the - * default NTP port and returns it. The time is the number of miliiseconds - * since 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. - * This method reads the raw NTP packet and constructs a <i>TimeInfo</i> - * object that allows access to all the fields of the NTP message header. - * <p> - * @param host The address of the server. - * @return The time value retrieved from the server. - * @throws IOException If an error occurs while retrieving the time. - */ - public TimeInfo getTime(final InetAddress host) throws IOException - { - return getTime(host, NtpV3Packet.NTP_PORT); - } - - /** - * Retrieves the time information from the specified server and port and - * returns it. The time is the number of miliiseconds since - * 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. - * This method reads the raw NTP packet and constructs a <i>TimeInfo</i> - * object that allows access to all the fields of the NTP message header. - * <p> - * @param host The address of the server. - * @param port The port of the service. - * @return The time value retrieved from the server. - * @throws IOException If an error occurs while retrieving the time or if - * received packet does not match the request. - */ - public TimeInfo getTime(final InetAddress host, final int port) throws IOException - { - // if not connected then open to next available UDP port - if (!isOpen()) - { - open(); - } - - final NtpV3Packet message = new NtpV3Impl(); - message.setMode(NtpV3Packet.MODE_CLIENT); - message.setVersion(version); - final DatagramPacket sendPacket = message.getDatagramPacket(); - sendPacket.setAddress(host); - sendPacket.setPort(port); - - final NtpV3Packet recMessage = new NtpV3Impl(); - final DatagramPacket receivePacket = recMessage.getDatagramPacket(); - - /* - * Must minimize the time between getting the current time, - * timestamping the packet, and sending it out which - * introduces an error in the delay time. - * No extraneous logging and initializations here !!! - */ - final TimeStamp now = TimeStamp.getCurrentTime(); - - // Note that if you do not set the transmit time field then originating time - // in server response is all 0's which is "Thu Feb 07 01:28:16 EST 2036". - message.setTransmitTime(now); - - _socket_.send(sendPacket); - _socket_.receive(receivePacket); - - final long returnTimeMillis = System.currentTimeMillis(); - - // Prevent invalid time information if response does not match request - if (!now.equals(recMessage.getOriginateTimeStamp())) - { - throw new IOException("Originate time does not match the request"); - } - - // create TimeInfo message container but don't pre-compute the details yet - return new TimeInfo(recMessage, returnTimeMillis, false); - } - - /** - * Returns the NTP protocol version number that client sets on request packet - * that is sent to remote host (e.g. 3=NTP v3, 4=NTP v4, etc.) - * - * @return the NTP protocol version number that client sets on request packet. - * @see #setVersion(int) - */ - public int getVersion() - { - return version; - } - - /** - * Sets the NTP protocol version number that client sets on request packet - * communicate with remote host. - * - * @param version the NTP protocol version number - */ - public void setVersion(final int version) - { - this.version = version; - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ntp; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; + +import org.apache.commons.net.DatagramSocketClient; + +/** + * The NTPUDPClient class is a UDP implementation of a client for the + * Network Time Protocol (NTP) described in RFC 1305 as well as the + * Simple Network Time Protocol (SNTP) in RFC-2030. To use the class, + * merely open a local datagram socket with <a href="#open"> open </a> + * and call <a href="#getTime"> getTime </a> to retrieve the time. Then call + * <a href="org.apache.commons.net.DatagramSocketClient.html#close"> close </a> + * to close the connection properly. + * Successive calls to <a href="#getTime"> getTime </a> are permitted + * without re-establishing a connection. That is because UDP is a + * connectionless protocol and the Network Time Protocol is stateless. + * + */ + +public final class NTPUDPClient extends DatagramSocketClient +{ + /** The default NTP port. It is set to 123 according to RFC 1305. */ + public static final int DEFAULT_PORT = 123; + + private int version = NtpV3Packet.VERSION_3; + + /** + * Retrieves the time information from the specified server on the + * default NTP port and returns it. The time is the number of miliiseconds + * since 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. + * This method reads the raw NTP packet and constructs a <i>TimeInfo</i> + * object that allows access to all the fields of the NTP message header. + * <p> + * @param host The address of the server. + * @return The time value retrieved from the server. + * @throws IOException If an error occurs while retrieving the time. + */ + public TimeInfo getTime(final InetAddress host) throws IOException + { + return getTime(host, NtpV3Packet.NTP_PORT); + } + + /** + * Retrieves the time information from the specified server and port and + * returns it. The time is the number of miliiseconds since + * 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. + * This method reads the raw NTP packet and constructs a <i>TimeInfo</i> + * object that allows access to all the fields of the NTP message header. + * <p> + * @param host The address of the server. + * @param port The port of the service. + * @return The time value retrieved from the server. + * @throws IOException If an error occurs while retrieving the time or if + * received packet does not match the request. + */ + public TimeInfo getTime(final InetAddress host, final int port) throws IOException + { + // if not connected then open to next available UDP port + if (!isOpen()) + { + open(); + } + + final NtpV3Packet message = new NtpV3Impl(); + message.setMode(NtpV3Packet.MODE_CLIENT); + message.setVersion(version); + final DatagramPacket sendPacket = message.getDatagramPacket(); + sendPacket.setAddress(host); + sendPacket.setPort(port); + + final NtpV3Packet recMessage = new NtpV3Impl(); + final DatagramPacket receivePacket = recMessage.getDatagramPacket(); + + /* + * Must minimize the time between getting the current time, + * timestamping the packet, and sending it out which + * introduces an error in the delay time. + * No extraneous logging and initializations here !!! + */ + final TimeStamp now = TimeStamp.getCurrentTime(); + + // Note that if you do not set the transmit time field then originating time + // in server response is all 0's which is "Thu Feb 07 01:28:16 EST 2036". + message.setTransmitTime(now); + + _socket_.send(sendPacket); + _socket_.receive(receivePacket); + + final long returnTimeMillis = System.currentTimeMillis(); + + // Prevent invalid time information if response does not match request + if (!now.equals(recMessage.getOriginateTimeStamp())) + { + throw new IOException("Originate time does not match the request"); + } + + // create TimeInfo message container but don't pre-compute the details yet + return new TimeInfo(recMessage, returnTimeMillis, false); + } + + /** + * Returns the NTP protocol version number that client sets on request packet + * that is sent to remote host (e.g. 3=NTP v3, 4=NTP v4, etc.) + * + * @return the NTP protocol version number that client sets on request packet. + * @see #setVersion(int) + */ + public int getVersion() + { + return version; + } + + /** + * Sets the NTP protocol version number that client sets on request packet + * communicate with remote host. + * + * @param version the NTP protocol version number + */ + public void setVersion(final int version) + { + this.version = version; + } + +} diff --git a/src/main/java/org/apache/commons/net/ntp/NtpUtils.java b/src/main/java/org/apache/commons/net/ntp/NtpUtils.java index 548c0c10..6164779b 100644 --- a/src/main/java/org/apache/commons/net/ntp/NtpUtils.java +++ b/src/main/java/org/apache/commons/net/ntp/NtpUtils.java @@ -1,115 +1,115 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * Common NtpUtils Helper class. - * - */ -public final class NtpUtils { - - /** - * Returns 32-bit integer address to IPv4 address string "%d.%d.%d.%d" format. - * - * @param address the 32-bit address - * @return the raw IP address in a string format. - */ - public static String getHostAddress(final int address) - { - return ((address >>> 24) & 0xFF) + "." + - ((address >>> 16) & 0xFF) + "." + - ((address >>> 8) & 0xFF) + "." + - ((address >>> 0) & 0xFF); - } - - /** - * Return human-readable name of message mode type (RFC 1305). - * - * @param mode the mode type - * @return mode name - */ - public static String getModeName(final int mode) - { - switch (mode) { - case NtpV3Packet.MODE_RESERVED: - return "Reserved"; - case NtpV3Packet.MODE_SYMMETRIC_ACTIVE: - return "Symmetric Active"; - case NtpV3Packet.MODE_SYMMETRIC_PASSIVE: - return "Symmetric Passive"; - case NtpV3Packet.MODE_CLIENT: - return "Client"; - case NtpV3Packet.MODE_SERVER: - return "Server"; - case NtpV3Packet.MODE_BROADCAST: - return "Broadcast"; - case NtpV3Packet.MODE_CONTROL_MESSAGE: - return "Control"; - case NtpV3Packet.MODE_PRIVATE: - return "Private"; - default: - return "Unknown"; - } - } - - /** - * Returns NTP packet reference identifier as IP address. - * - * @param packet NTP packet - * @return the packet reference id (as IP address) in "%d.%d.%d.%d" format. - */ - public static String getRefAddress(final NtpV3Packet packet) - { - final int address = (packet == null) ? 0 : packet.getReferenceId(); - return getHostAddress(address); - } - - /** - * Get refId as reference clock string (e.g. GPS, WWV, LCL). If string is - * invalid (non-ASCII character) then returns empty string "". - * For details refer to the <A HREF="http://www.eecis.udel.edu/~mills/ntp/html/refclock.html#list">Comprehensive - * List of Clock Drivers</A>. - * - * @param message the message to check - * @return reference clock string if primary NTP server - */ - public static String getReferenceClock(final NtpV3Packet message) { - if (message == null) { - return ""; - } - final int refId = message.getReferenceId(); - if (refId == 0) { - return ""; - } - final StringBuilder buf = new StringBuilder(4); - // start at highest-order byte (0x4c434c00 -> LCL) - for (int shiftBits = 24; shiftBits >= 0; shiftBits -= 8) - { - final char c = (char) ((refId >>> shiftBits) & 0xff); - if (c == 0) { // 0-terminated ASCII string - break; - } - if (!Character.isLetterOrDigit(c)) { - return ""; - } - buf.append(c); - } - return buf.toString(); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ntp; + +/** + * Common NtpUtils Helper class. + * + */ +public final class NtpUtils { + + /** + * Returns 32-bit integer address to IPv4 address string "%d.%d.%d.%d" format. + * + * @param address the 32-bit address + * @return the raw IP address in a string format. + */ + public static String getHostAddress(final int address) + { + return ((address >>> 24) & 0xFF) + "." + + ((address >>> 16) & 0xFF) + "." + + ((address >>> 8) & 0xFF) + "." + + ((address >>> 0) & 0xFF); + } + + /** + * Return human-readable name of message mode type (RFC 1305). + * + * @param mode the mode type + * @return mode name + */ + public static String getModeName(final int mode) + { + switch (mode) { + case NtpV3Packet.MODE_RESERVED: + return "Reserved"; + case NtpV3Packet.MODE_SYMMETRIC_ACTIVE: + return "Symmetric Active"; + case NtpV3Packet.MODE_SYMMETRIC_PASSIVE: + return "Symmetric Passive"; + case NtpV3Packet.MODE_CLIENT: + return "Client"; + case NtpV3Packet.MODE_SERVER: + return "Server"; + case NtpV3Packet.MODE_BROADCAST: + return "Broadcast"; + case NtpV3Packet.MODE_CONTROL_MESSAGE: + return "Control"; + case NtpV3Packet.MODE_PRIVATE: + return "Private"; + default: + return "Unknown"; + } + } + + /** + * Returns NTP packet reference identifier as IP address. + * + * @param packet NTP packet + * @return the packet reference id (as IP address) in "%d.%d.%d.%d" format. + */ + public static String getRefAddress(final NtpV3Packet packet) + { + final int address = (packet == null) ? 0 : packet.getReferenceId(); + return getHostAddress(address); + } + + /** + * Get refId as reference clock string (e.g. GPS, WWV, LCL). If string is + * invalid (non-ASCII character) then returns empty string "". + * For details refer to the <A HREF="http://www.eecis.udel.edu/~mills/ntp/html/refclock.html#list">Comprehensive + * List of Clock Drivers</A>. + * + * @param message the message to check + * @return reference clock string if primary NTP server + */ + public static String getReferenceClock(final NtpV3Packet message) { + if (message == null) { + return ""; + } + final int refId = message.getReferenceId(); + if (refId == 0) { + return ""; + } + final StringBuilder buf = new StringBuilder(4); + // start at highest-order byte (0x4c434c00 -> LCL) + for (int shiftBits = 24; shiftBits >= 0; shiftBits -= 8) + { + final char c = (char) ((refId >>> shiftBits) & 0xff); + if (c == 0) { // 0-terminated ASCII string + break; + } + if (!Character.isLetterOrDigit(c)) { + return ""; + } + buf.append(c); + } + return buf.toString(); + } + +} diff --git a/src/main/java/org/apache/commons/net/ntp/NtpV3Impl.java b/src/main/java/org/apache/commons/net/ntp/NtpV3Impl.java index 650c854e..318a7145 100644 --- a/src/main/java/org/apache/commons/net/ntp/NtpV3Impl.java +++ b/src/main/java/org/apache/commons/net/ntp/NtpV3Impl.java @@ -1,698 +1,699 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.net.DatagramPacket; - -/** - * Implementation of NtpV3Packet with methods converting Java objects to/from - * the Network Time Protocol (NTP) data message header format described in RFC-1305. - * - */ -public class NtpV3Impl implements NtpV3Packet -{ - - private static final int MODE_INDEX = 0; - private static final int MODE_SHIFT = 0; - - private static final int VERSION_INDEX = 0; - private static final int VERSION_SHIFT = 3; - - private static final int LI_INDEX = 0; - private static final int LI_SHIFT = 6; - - private static final int STRATUM_INDEX = 1; - private static final int POLL_INDEX = 2; - private static final int PRECISION_INDEX = 3; - - private static final int ROOT_DELAY_INDEX = 4; - private static final int ROOT_DISPERSION_INDEX = 8; - private static final int REFERENCE_ID_INDEX = 12; - - private static final int REFERENCE_TIMESTAMP_INDEX = 16; - private static final int ORIGINATE_TIMESTAMP_INDEX = 24; - private static final int RECEIVE_TIMESTAMP_INDEX = 32; - private static final int TRANSMIT_TIMESTAMP_INDEX = 40; - -// private static final int KEY_IDENTIFIER_INDEX = 48; -// private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */ - - /** - * Convert byte to unsigned integer. - * Java only has signed types so we have to do - * more work to get unsigned ops. - * - * @param b input byte - * @return unsigned int value of byte - */ - protected static final int ui(final byte b) - { - final int i = b & 0xFF; - return i; - } - - /** - * Convert byte to unsigned long. - * Java only has signed types so we have to do - * more work to get unsigned ops - * - * @param b input byte - * @return unsigned long value of byte - */ - protected static final long ul(final byte b) - { - final long i = b & 0xFF; - return i; - } - - private final byte[] buf = new byte[48]; - - private volatile DatagramPacket dp; - - /** Creates a new instance of NtpV3Impl */ - public NtpV3Impl() - { - } - - /** - * Compares this object against the specified object. - * The result is <code>true</code> if and only if the argument is - * not <code>null</code> and is a <code>NtpV3Impl</code> object that - * contains the same values as this object. - * - * @param obj the object to compare with. - * @return <code>true</code> if the objects are the same; - * <code>false</code> otherwise. - * @since 3.4 - */ - @Override - public boolean equals(final Object obj) - { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final NtpV3Impl other = (NtpV3Impl) obj; - return java.util.Arrays.equals(buf, other.buf); - } - - /** - * Returns the datagram packet with the NTP details already filled in. - * - * @return a datagram packet. - */ - @Override - public synchronized DatagramPacket getDatagramPacket() - { - if (dp == null) { - dp = new DatagramPacket(buf, buf.length); - dp.setPort(NTP_PORT); - } - return dp; - } - - /** - * @return 4 bytes as 32-bit int - */ - private int getInt(final int index) - { - final int i = ui(buf[index]) << 24 | - ui(buf[index + 1]) << 16 | - ui(buf[index + 2]) << 8 | - ui(buf[index + 3]); - - return i; - } - - /** - * Returns leap indicator as defined in RFC-1305 which is a two-bit code: - * 0=no warning - * 1=last minute has 61 seconds - * 2=last minute has 59 seconds - * 3=alarm condition (clock not synchronized) - * - * @return leap indicator as defined in RFC-1305. - */ - @Override - public int getLeapIndicator() - { - return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3; - } - - /** - * Get Long value represented by bits starting at specified index. - * - * @return 8 bytes as 64-bit long - */ - private long getLong(final int index) - { - final long i = ul(buf[index]) << 56 | - ul(buf[index + 1]) << 48 | - ul(buf[index + 2]) << 40 | - ul(buf[index + 3]) << 32 | - ul(buf[index + 4]) << 24 | - ul(buf[index + 5]) << 16 | - ul(buf[index + 6]) << 8 | - ul(buf[index + 7]); - return i; - } - - /** - * Returns mode as defined in RFC-1305 which is a 3-bit integer - * whose value is indicated by the MODE_xxx parameters. - * - * @return mode as defined in RFC-1305. - */ - @Override - public int getMode() - { - return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7; - } - - /** - * Return human-readable name of message mode type as described in - * RFC 1305. - * @return mode name as string. - */ - @Override - public String getModeName() - { - return NtpUtils.getModeName(getMode()); - } - - /** - * Returns the originate time as defined in RFC-1305. - * - * @return the originate time. - * Never returns null. - */ - @Override - public TimeStamp getOriginateTimeStamp() - { - return getTimestamp(ORIGINATE_TIMESTAMP_INDEX); - } - - /** - * Returns poll interval as defined in RFC-1305, which is an eight-bit - * signed integer indicating the maximum interval between successive - * messages, in seconds to the nearest power of two (e.g. value of six - * indicates an interval of 64 seconds. The values that can appear in - * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive. - * - * @return poll interval as defined in RFC-1305. - */ - @Override - public int getPoll() - { - return buf[POLL_INDEX]; - } - - /** - * Returns precision as defined in RFC-1305 encoded as an 8-bit signed - * integer (seconds to nearest power of two). - * Values normally range from -6 to -20. - * - * @return precision as defined in RFC-1305. - */ - @Override - public int getPrecision() - { - return buf[PRECISION_INDEX]; - } - - /** - * Returns receive timestamp as defined in RFC-1305. - * - * @return the receive time. - * Never returns null. - */ - @Override - public TimeStamp getReceiveTimeStamp() - { - return getTimestamp(RECEIVE_TIMESTAMP_INDEX); - } - - /** - * Returns the reference id as defined in RFC-1305, which is - * a 32-bit integer whose value is dependent on several criteria. - * - * @return the reference id as defined in RFC-1305. - */ - @Override - public int getReferenceId() - { - return getInt(REFERENCE_ID_INDEX); - } - - /** - * Returns the reference id string. String cannot be null but - * value is dependent on the version of the NTP spec supported - * and stratum level. Value can be an empty string, clock type string, - * IP address, or a hex string. - * - * @return the reference id string. - */ - @Override - public String getReferenceIdString() - { - final int version = getVersion(); - final int stratum = getStratum(); - if (version == VERSION_3 || version == VERSION_4) { - if (stratum == 0 || stratum == 1) { - return idAsString(); // 4-character ASCII string (e.g. GPS, USNO) - } - // in NTPv4 servers this is latest transmit timestamp of ref source - if (version == VERSION_4) { - return idAsHex(); - } - } - - // Stratum 2 and higher this is a four-octet IPv4 address - // of the primary reference host. - if (stratum >= 2) { - return idAsIPAddress(); - } - return idAsHex(); - } - - /** - * Returns the reference time as defined in RFC-1305. - * - * @return the reference time as <code>TimeStamp</code> object. - * Never returns null. - */ - @Override - public TimeStamp getReferenceTimeStamp() - { - return getTimestamp(REFERENCE_TIMESTAMP_INDEX); - } - - /** - * Return root delay as defined in RFC-1305, which is the total roundtrip delay - * to the primary reference source, in seconds. Values can take positive and - * negative values, depending on clock precision and skew. - * - * @return root delay as defined in RFC-1305. - */ - @Override - public int getRootDelay() - { - return getInt(ROOT_DELAY_INDEX); - } - - /** - * Return root delay as defined in RFC-1305 in milliseconds, which is - * the total roundtrip delay to the primary reference source, in - * seconds. Values can take positive and negative values, depending - * on clock precision and skew. - * - * @return root delay in milliseconds - */ - @Override - public double getRootDelayInMillisDouble() - { - final double l = getRootDelay(); - return l / 65.536; - } - - /** - * Returns root dispersion as defined in RFC-1305. - * @return root dispersion. - */ - @Override - public int getRootDispersion() - { - return getInt(ROOT_DISPERSION_INDEX); - } - - /** - * Returns root dispersion (as defined in RFC-1305) in milliseconds. - * - * @return root dispersion in milliseconds - */ - @Override - public long getRootDispersionInMillis() - { - final long l = getRootDispersion(); - return (l * 1000) / 65536L; - } - - /** - * Returns root dispersion (as defined in RFC-1305) in milliseconds - * as double precision value. - * - * @return root dispersion in milliseconds - */ - @Override - public double getRootDispersionInMillisDouble() - { - final double l = getRootDispersion(); - return l / 65.536; - } - - /** - * Returns Stratum as defined in RFC-1305, which indicates the stratum level - * of the local clock, with values defined as follows: 0=unspecified, - * 1=primary ref clock, and all others a secondary reference (via NTP). - * - * @return Stratum level as defined in RFC-1305. - */ - @Override - public int getStratum() - { - return ui(buf[STRATUM_INDEX]); - } - - /** - * Get NTP Timestamp at specified starting index. - * - * @param index index into data array - * @return TimeStamp object for 64 bits starting at index - */ - private TimeStamp getTimestamp(final int index) - { - return new TimeStamp(getLong(index)); - } - - /** - * Returns the transmit timestamp as defined in RFC-1305. - * - * @return the transmit timestamp as defined in RFC-1305. - * Never returns a null object. - */ - @Override - public TimeStamp getTransmitTimeStamp() - { - return getTimestamp(TRANSMIT_TIMESTAMP_INDEX); - } - - /** - * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) - * correspond to the protocol used to obtain the timing information. - * - * @return packet type string identifier which in this case is "NTP". - */ - @Override - public String getType() - { - return "NTP"; - } - - /** - * Returns NTP version number as defined in RFC-1305. - * - * @return NTP version number. - */ - @Override - public int getVersion() - { - return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7; - } - - /** - * Computes a hashcode for this object. The result is the exclusive - * OR of the values of this object stored as a byte array. - * - * @return a hash code value for this object. - * @since 3.4 - */ - @Override - public int hashCode() - { - return java.util.Arrays.hashCode(buf); - } - - private String idAsHex() - { - return Integer.toHexString(getReferenceId()); - } - - /** - * Returns Reference id as dotted IP address. - * @return refId as IP address string. - */ - private String idAsIPAddress() - { - return ui(buf[REFERENCE_ID_INDEX]) + "." + - ui(buf[REFERENCE_ID_INDEX + 1]) + "." + - ui(buf[REFERENCE_ID_INDEX + 2]) + "." + - ui(buf[REFERENCE_ID_INDEX + 3]); - } - - private String idAsString() - { - final StringBuilder id = new StringBuilder(); - for (int i = 0; i <= 3; i++) { - final char c = (char) buf[REFERENCE_ID_INDEX + i]; - if (c == 0) { // 0-terminated string - break; - } - id.append(c); - } - return id.toString(); - } - - /** - * Set the contents of this object from source datagram packet. - * - * @param srcDp source DatagramPacket to copy contents from, never null. - * @throws IllegalArgumentException if srcDp is null or byte length is less than minimum length of 48 bytes - */ - @Override - public void setDatagramPacket(final DatagramPacket srcDp) - { - if (srcDp == null || srcDp.getLength() < buf.length) { - throw new IllegalArgumentException(); - } - final byte[] incomingBuf = srcDp.getData(); - int len = srcDp.getLength(); - if (len > buf.length) { - len = buf.length; - } - System.arraycopy(incomingBuf, 0, buf, 0, len); - final DatagramPacket dp = getDatagramPacket(); - dp.setAddress(srcDp.getAddress()); - final int port = srcDp.getPort(); - dp.setPort(port > 0 ? port : NTP_PORT); - dp.setData(buf); - } - - /** - * Set integer value at index position. - * - * @param idx index position - * @param value 32-bit int value - */ - private void setInt(final int idx, int value) - { - for (int i=3; i >= 0; i--) { - buf[idx + i] = (byte) (value & 0xff); - value >>>= 8; // shift right one-byte - } - } - - /** - * Set leap indicator as defined in RFC-1305. - * - * @param li leap indicator. - */ - @Override - public void setLeapIndicator(final int li) - { - buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT)); - } - - /** - * Set mode as defined in RFC-1305. - * - * @param mode the mode to set - */ - @Override - public void setMode(final int mode) - { - buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7); - } - - /** - * Set originate timestamp given NTP TimeStamp object. - * If <code>ts</code> is null then zero time is used. - * - * @param ts NTP timestamp - */ - @Override - public void setOriginateTimeStamp(final TimeStamp ts) - { - setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts); - } - - /** - * Set poll interval as defined in RFC-1305. - * - * @param poll poll interval. - */ - @Override - public void setPoll(final int poll) - { - buf[POLL_INDEX] = (byte) (poll & 0xFF); - } - - /** - * Set precision as defined in RFC-1305. - * @param precision the precision to set - * @since 3.4 - */ - @Override - public void setPrecision(final int precision) - { - buf[PRECISION_INDEX] = (byte) (precision & 0xFF); - } - - /** - * Set receive timestamp given NTP TimeStamp object. - * If <code>ts</code> is null then zero time is used. - * - * @param ts timestamp - */ - @Override - public void setReceiveTimeStamp(final TimeStamp ts) - { - setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts); - } - - /** - * Set reference clock identifier field with 32-bit unsigned integer value. - * See RFC-1305 for description. - * - * @param refId reference clock identifier. - */ - @Override - public void setReferenceId(final int refId) - { - setInt(REFERENCE_ID_INDEX, refId); - } - - /** - * Set Reference time with NTP timestamp. If <code>ts</code> is null - * then zero time is used. - * - * @param ts NTP timestamp - */ - @Override - public void setReferenceTime(final TimeStamp ts) - { - setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts); - } - - /** - * Set root delay as defined in RFC-1305. - * - * @param delay root delay - * @since 3.4 - */ - @Override - public void setRootDelay(final int delay) - { - setInt(ROOT_DELAY_INDEX, delay); - } - - /** - * Set root dispersion as defined in RFC-1305. - * - * @param dispersion root dispersion - * @since 3.4 - */ - @Override - public void setRootDispersion(final int dispersion) - { - setInt(ROOT_DISPERSION_INDEX, dispersion); - } - - /** - * Set stratum level as defined in RFC-1305. - * - * @param stratum stratum level. - */ - @Override - public void setStratum(final int stratum) - { - buf[STRATUM_INDEX] = (byte) (stratum & 0xFF); - } - - /** - * Sets the NTP timestamp at the given array index. - * - * @param index index into the byte array. - * @param t TimeStamp. - */ - private void setTimestamp(final int index, final TimeStamp t) - { - long ntpTime = (t == null) ? 0 : t.ntpValue(); - // copy 64-bits from Long value into 8 x 8-bit bytes of array - // one byte at a time shifting 8-bits for each position. - for (int i = 7; i >= 0; i--) { - buf[index + i] = (byte) (ntpTime & 0xFF); - ntpTime >>>= 8; // shift to next byte - } - // buf[index] |= 0x80; // only set if 1900 baseline.... - } - - /** - * Set transmit time with NTP timestamp. - * If <code>ts</code> is null then zero time is used. - * - * @param ts NTP timestamp - */ - @Override - public void setTransmitTime(final TimeStamp ts) - { - setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts); - } - - /** - * Set NTP version as defined in RFC-1305. - * - * @param version NTP version. - */ - @Override - public void setVersion(final int version) - { - buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT)); - } - - /** - * Returns details of NTP packet as a string. - * - * @return details of NTP packet as a string. - */ - @Override - public String toString() - { - return "[" + - "version:" + getVersion() + - ", mode:" + getMode() + - ", poll:" + getPoll() + - ", precision:" + getPrecision() + - ", delay:" + getRootDelay() + - ", dispersion(ms):" + getRootDispersionInMillisDouble() + - ", id:" + getReferenceIdString() + - ", xmitTime:" + getTransmitTimeStamp().toDateString() + - " ]"; - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ntp; + +import java.net.DatagramPacket; + +/** + * Implementation of NtpV3Packet with methods converting Java objects to/from + * the Network Time Protocol (NTP) data message header format described in RFC-1305. + * + */ +public class NtpV3Impl implements NtpV3Packet +{ + + private static final int MODE_INDEX = 0; + private static final int MODE_SHIFT = 0; + + private static final int VERSION_INDEX = 0; + private static final int VERSION_SHIFT = 3; + + private static final int LI_INDEX = 0; + private static final int LI_SHIFT = 6; + + private static final int STRATUM_INDEX = 1; + private static final int POLL_INDEX = 2; + private static final int PRECISION_INDEX = 3; + + private static final int ROOT_DELAY_INDEX = 4; + private static final int ROOT_DISPERSION_INDEX = 8; + private static final int REFERENCE_ID_INDEX = 12; + + private static final int REFERENCE_TIMESTAMP_INDEX = 16; + private static final int ORIGINATE_TIMESTAMP_INDEX = 24; + private static final int RECEIVE_TIMESTAMP_INDEX = 32; + private static final int TRANSMIT_TIMESTAMP_INDEX = 40; + +// private static final int KEY_IDENTIFIER_INDEX = 48; +// private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */ + + /** + * Convert byte to unsigned integer. + * Java only has signed types so we have to do + * more work to get unsigned ops. + * + * @param b input byte + * @return unsigned int value of byte + */ + protected static final int ui(final byte b) + { + final int i = b & 0xFF; + return i; + } + + /** + * Convert byte to unsigned long. + * Java only has signed types so we have to do + * more work to get unsigned ops + * + * @param b input byte + * @return unsigned long value of byte + */ + protected static final long ul(final byte b) + { + final long i = b & 0xFF; + return i; + } + + private final byte[] buf = new byte[48]; + + private volatile DatagramPacket dp; + + /** Creates a new instance of NtpV3Impl */ + public NtpV3Impl() + { + } + + /** + * Compares this object against the specified object. + * The result is <code>true</code> if and only if the argument is + * not <code>null</code> and is a <code>NtpV3Impl</code> object that + * contains the same values as this object. + * + * @param obj the object to compare with. + * @return <code>true</code> if the objects are the same; + * <code>false</code> otherwise. + * @since 3.4 + */ + @Override + public boolean equals(final Object obj) + { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final NtpV3Impl other = (NtpV3Impl) obj; + return java.util.Arrays.equals(buf, other.buf); + } + + /** + * Returns the datagram packet with the NTP details already filled in. + * + * @return a datagram packet. + */ + @Override + public synchronized DatagramPacket getDatagramPacket() + { + if (dp == null) { + dp = new DatagramPacket(buf, buf.length); + dp.setPort(NTP_PORT); + } + return dp; + } + + /** + * @return 4 bytes as 32-bit int + */ + private int getInt(final int index) + { + final int i = ui(buf[index]) << 24 | + ui(buf[index + 1]) << 16 | + ui(buf[index + 2]) << 8 | + ui(buf[index + 3]); + + return i; + } + + /** + * Returns leap indicator as defined in RFC-1305 which is a two-bit code: + * 0=no warning + * 1=last minute has 61 seconds + * 2=last minute has 59 seconds + * 3=alarm condition (clock not synchronized) + * + * @return leap indicator as defined in RFC-1305. + */ + @Override + public int getLeapIndicator() + { + return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3; + } + + /** + * Get Long value represented by bits starting at specified index. + * + * @return 8 bytes as 64-bit long + */ + private long getLong(final int index) + { + final long i = ul(buf[index]) << 56 | + ul(buf[index + 1]) << 48 | + ul(buf[index + 2]) << 40 | + ul(buf[index + 3]) << 32 | + ul(buf[index + 4]) << 24 | + ul(buf[index + 5]) << 16 | + ul(buf[index + 6]) << 8 | + ul(buf[index + 7]); + return i; + } + + /** + * Returns mode as defined in RFC-1305 which is a 3-bit integer + * whose value is indicated by the MODE_xxx parameters. + * + * @return mode as defined in RFC-1305. + */ + @Override + public int getMode() + { + return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7; + } + + /** + * Return human-readable name of message mode type as described in + * RFC 1305. + * @return mode name as string. + */ + @Override + public String getModeName() + { + return NtpUtils.getModeName(getMode()); + } + + /** + * Returns the originate time as defined in RFC-1305. + * + * @return the originate time. + * Never returns null. + */ + @Override + public TimeStamp getOriginateTimeStamp() + { + return getTimestamp(ORIGINATE_TIMESTAMP_INDEX); + } + + /** + * Returns poll interval as defined in RFC-1305, which is an eight-bit + * signed integer indicating the maximum interval between successive + * messages, in seconds to the nearest power of two (e.g. value of six + * indicates an interval of 64 seconds. The values that can appear in + * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive. + * + * @return poll interval as defined in RFC-1305. + */ + @Override + public int getPoll() + { + return buf[POLL_INDEX]; + } + + /** + * Returns precision as defined in RFC-1305 encoded as an 8-bit signed + * integer (seconds to nearest power of two). + * Values normally range from -6 to -20. + * + * @return precision as defined in RFC-1305. + */ + @Override + public int getPrecision() + { + return buf[PRECISION_INDEX]; + } + + /** + * Returns receive timestamp as defined in RFC-1305. + * + * @return the receive time. + * Never returns null. + */ + @Override + public TimeStamp getReceiveTimeStamp() + { + return getTimestamp(RECEIVE_TIMESTAMP_INDEX); + } + + /** + * Returns the reference id as defined in RFC-1305, which is + * a 32-bit integer whose value is dependent on several criteria. + * + * @return the reference id as defined in RFC-1305. + */ + @Override + public int getReferenceId() + { + return getInt(REFERENCE_ID_INDEX); + } + + /** + * Returns the reference id string. String cannot be null but + * value is dependent on the version of the NTP spec supported + * and stratum level. Value can be an empty string, clock type string, + * IP address, or a hex string. + * + * @return the reference id string. + */ + @Override + public String getReferenceIdString() + { + final int version = getVersion(); + final int stratum = getStratum(); + if (version == VERSION_3 || version == VERSION_4) { + if (stratum == 0 || stratum == 1) { + return idAsString(); // 4-character ASCII string (e.g. GPS, USNO) + } + // in NTPv4 servers this is latest transmit timestamp of ref source + if (version == VERSION_4) { + return idAsHex(); + } + } + + // Stratum 2 and higher this is a four-octet IPv4 address + // of the primary reference host. + if (stratum >= 2) { + return idAsIPAddress(); + } + return idAsHex(); + } + + /** + * Returns the reference time as defined in RFC-1305. + * + * @return the reference time as <code>TimeStamp</code> object. + * Never returns null. + */ + @Override + public TimeStamp getReferenceTimeStamp() + { + return getTimestamp(REFERENCE_TIMESTAMP_INDEX); + } + + /** + * Return root delay as defined in RFC-1305, which is the total roundtrip delay + * to the primary reference source, in seconds. Values can take positive and + * negative values, depending on clock precision and skew. + * + * @return root delay as defined in RFC-1305. + */ + @Override + public int getRootDelay() + { + return getInt(ROOT_DELAY_INDEX); + } + + /** + * Return root delay as defined in RFC-1305 in milliseconds, which is + * the total roundtrip delay to the primary reference source, in + * seconds. Values can take positive and negative values, depending + * on clock precision and skew. + * + * @return root delay in milliseconds + */ + @Override + public double getRootDelayInMillisDouble() + { + final double l = getRootDelay(); + return l / 65.536; + } + + /** + * Returns root dispersion as defined in RFC-1305. + * @return root dispersion. + */ + @Override + public int getRootDispersion() + { + return getInt(ROOT_DISPERSION_INDEX); + } + + /** + * Returns root dispersion (as defined in RFC-1305) in milliseconds. + * + * @return root dispersion in milliseconds + */ + @Override + public long getRootDispersionInMillis() + { + final long l = getRootDispersion(); + return (l * 1000) / 65536L; + } + + /** + * Returns root dispersion (as defined in RFC-1305) in milliseconds + * as double precision value. + * + * @return root dispersion in milliseconds + */ + @Override + public double getRootDispersionInMillisDouble() + { + final double l = getRootDispersion(); + return l / 65.536; + } + + /** + * Returns Stratum as defined in RFC-1305, which indicates the stratum level + * of the local clock, with values defined as follows: 0=unspecified, + * 1=primary ref clock, and all others a secondary reference (via NTP). + * + * @return Stratum level as defined in RFC-1305. + */ + @Override + public int getStratum() + { + return ui(buf[STRATUM_INDEX]); + } + + /** + * Get NTP Timestamp at specified starting index. + * + * @param index index into data array + * @return TimeStamp object for 64 bits starting at index + */ + private TimeStamp getTimestamp(final int index) + { + return new TimeStamp(getLong(index)); + } + + /** + * Returns the transmit timestamp as defined in RFC-1305. + * + * @return the transmit timestamp as defined in RFC-1305. + * Never returns a null object. + */ + @Override + public TimeStamp getTransmitTimeStamp() + { + return getTimestamp(TRANSMIT_TIMESTAMP_INDEX); + } + + /** + * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) + * correspond to the protocol used to obtain the timing information. + * + * @return packet type string identifier which in this case is "NTP". + */ + @Override + public String getType() + { + return "NTP"; + } + + /** + * Returns NTP version number as defined in RFC-1305. + * + * @return NTP version number. + */ + @Override + public int getVersion() + { + return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7; + } + + /** + * Computes a hashcode for this object. The result is the exclusive + * OR of the values of this object stored as a byte array. + * + * @return a hash code value for this object. + * @since 3.4 + */ + @Override + public int hashCode() + { + return java.util.Arrays.hashCode(buf); + } + + private String idAsHex() + { + return Integer.toHexString(getReferenceId()); + } + + /** + * Returns Reference id as dotted IP address. + * @return refId as IP address string. + */ + private String idAsIPAddress() + { + return ui(buf[REFERENCE_ID_INDEX]) + "." + + ui(buf[REFERENCE_ID_INDEX + 1]) + "." + + ui(buf[REFERENCE_ID_INDEX + 2]) + "." + + ui(buf[REFERENCE_ID_INDEX + 3]); + } + + private String idAsString() + { + final StringBuilder id = new StringBuilder(); + for (int i = 0; i <= 3; i++) { + final char c = (char) buf[REFERENCE_ID_INDEX + i]; + if (c == 0) { // 0-terminated string + break; + } + id.append(c); + } + return id.toString(); + } + + /** + * Set the contents of this object from source datagram packet. + * + * @param srcDp source DatagramPacket to copy contents from, never null. + * @throws IllegalArgumentException if srcDp is null or byte length is less than minimum length of 48 bytes + */ + @Override + public void setDatagramPacket(final DatagramPacket srcDp) + { + if (srcDp == null || srcDp.getLength() < buf.length) { + throw new IllegalArgumentException(); + } + final byte[] incomingBuf = srcDp.getData(); + int len = srcDp.getLength(); + if (len > buf.length) { + len = buf.length; + } + System.arraycopy(incomingBuf, 0, buf, 0, len); + final DatagramPacket dp = getDatagramPacket(); + dp.setAddress(srcDp.getAddress()); + final int port = srcDp.getPort(); + dp.setPort(port > 0 ? port : NTP_PORT); + dp.setData(buf); + } + + /** + * Set integer value at index position. + * + * @param idx index position + * @param value 32-bit int value + */ + private void setInt(final int idx, int value) + { + for (int i=3; i >= 0; i--) { + buf[idx + i] = (byte) (value & 0xff); + value >>>= 8; // shift right one-byte + } + } + + /** + * Set leap indicator as defined in RFC-1305. + * + * @param li leap indicator. + */ + @Override + public void setLeapIndicator(final int li) + { + buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT)); + } + + /** + * Set mode as defined in RFC-1305. + * + * @param mode the mode to set + */ + @Override + public void setMode(final int mode) + { + buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7); + } + + /** + * Set originate timestamp given NTP TimeStamp object. + * If <code>ts</code> is null then zero time is used. + * + * @param ts NTP timestamp + */ + @Override + public void setOriginateTimeStamp(final TimeStamp ts) + { + setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts); + } + + /** + * Set poll interval as defined in RFC-1305. + * + * @param poll poll interval. + */ + @Override + public void setPoll(final int poll) + { + buf[POLL_INDEX] = (byte) (poll & 0xFF); + } + + /** + * Set precision as defined in RFC-1305. + * @param precision the precision to set + * @since 3.4 + */ + @Override + public void setPrecision(final int precision) + { + buf[PRECISION_INDEX] = (byte) (precision & 0xFF); + } + + /** + * Set receive timestamp given NTP TimeStamp object. + * If <code>ts</code> is null then zero time is used. + * + * @param ts timestamp + */ + @Override + public void setReceiveTimeStamp(final TimeStamp ts) + { + setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts); + } + + /** + * Set reference clock identifier field with 32-bit unsigned integer value. + * See RFC-1305 for description. + * + * @param refId reference clock identifier. + */ + @Override + public void setReferenceId(final int refId) + { + setInt(REFERENCE_ID_INDEX, refId); + } + + /** + * Set Reference time with NTP timestamp. If <code>ts</code> is null + * then zero time is used. + * + * @param ts NTP timestamp + */ + @Override + public void setReferenceTime(final TimeStamp ts) + { + setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts); + } + + /** + * Set root delay as defined in RFC-1305. + * + * @param delay root delay + * @since 3.4 + */ + @Override + public void setRootDelay(final int delay) + { + setInt(ROOT_DELAY_INDEX, delay); + } + + /** + * Set root dispersion as defined in RFC-1305. + * + * @param dispersion root dispersion + * @since 3.4 + */ + @Override + public void setRootDispersion(final int dispersion) + { + setInt(ROOT_DISPERSION_INDEX, dispersion); + } + + /** + * Set stratum level as defined in RFC-1305. + * + * @param stratum stratum level. + */ + @Override + public void setStratum(final int stratum) + { + buf[STRATUM_INDEX] = (byte) (stratum & 0xFF); + } + + /** + * Sets the NTP timestamp at the given array index. + * + * @param index index into the byte array. + * @param t TimeStamp. + */ + private void setTimestamp(final int index, final TimeStamp t) + { + long ntpTime = (t == null) ? 0 : t.ntpValue(); + // copy 64-bits from Long value into 8 x 8-bit bytes of array + // one byte at a time shifting 8-bits for each position. + for (int i = 7; i >= 0; i--) { + buf[index + i] = (byte) (ntpTime & 0xFF); + ntpTime >>>= 8; // shift to next byte + } + // buf[index] |= 0x80; // only set if 1900 baseline.... + } + + /** + * Set transmit time with NTP timestamp. + * If <code>ts</code> is null then zero time is used. + * + * @param ts NTP timestamp + */ + @Override + public void setTransmitTime(final TimeStamp ts) + { + setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts); + } + + /** + * Set NTP version as defined in RFC-1305. + * + * @param version NTP version. + */ + @Override + public void setVersion(final int version) + { + buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT)); + } + + /** + * Returns details of NTP packet as a string. + * + * @return details of NTP packet as a string. + */ + @Override + public String toString() + { + return "[" + + "version:" + getVersion() + + ", mode:" + getMode() + + ", poll:" + getPoll() + + ", precision:" + getPrecision() + + ", delay:" + getRootDelay() + + ", dispersion(ms):" + getRootDispersionInMillisDouble() + + ", id:" + getReferenceIdString() + + ", xmitTime:" + getTransmitTimeStamp().toDateString() + + " ]"; + } + +} diff --git a/src/main/java/org/apache/commons/net/ntp/NtpV3Packet.java b/src/main/java/org/apache/commons/net/ntp/NtpV3Packet.java index 353595b4..d9712854 100644 --- a/src/main/java/org/apache/commons/net/ntp/NtpV3Packet.java +++ b/src/main/java/org/apache/commons/net/ntp/NtpV3Packet.java @@ -1,259 +1,259 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.net.DatagramPacket; - -/** - * Interface for a NtpV3Packet with get/set methods corresponding to the fields - * in the NTP Data Message Header described in RFC 1305. - * - */ -public interface NtpV3Packet -{ - - /** - * Standard NTP UDP port - */ - int NTP_PORT = 123; - - int LI_NO_WARNING = 0; - int LI_LAST_MINUTE_HAS_61_SECONDS = 1; - int LI_LAST_MINUTE_HAS_59_SECONDS = 2; - int LI_ALARM_CONDITION = 3; - - /* mode options */ - int MODE_RESERVED = 0; - int MODE_SYMMETRIC_ACTIVE = 1; - int MODE_SYMMETRIC_PASSIVE = 2; - int MODE_CLIENT = 3; - int MODE_SERVER = 4; - int MODE_BROADCAST = 5; - int MODE_CONTROL_MESSAGE = 6; - int MODE_PRIVATE = 7; - - int NTP_MINPOLL = 4; // 16 seconds - int NTP_MAXPOLL = 14; // 16284 seconds - - int NTP_MINCLOCK = 1; - int NTP_MAXCLOCK = 10; - - int VERSION_3 = 3; - int VERSION_4 = 4; - - /* possible getType values such that other time-related protocols can - * have its information represented as NTP packets - */ - String TYPE_NTP = "NTP"; // RFC-1305/2030 - String TYPE_ICMP = "ICMP"; // RFC-792 - String TYPE_TIME = "TIME"; // RFC-868 - String TYPE_DAYTIME = "DAYTIME"; // RFC-867 - - /** - * @return a datagram packet with the NTP parts already filled in - */ - DatagramPacket getDatagramPacket(); - - /** - * @return leap indicator as defined in RFC-1305 - */ - int getLeapIndicator(); - - /** - * @return mode as defined in RFC-1305 - */ - int getMode(); - - /** - * @return mode as human readable string; e.g. 3=Client - */ - String getModeName(); - - /** - * @return the originate time as defined in RFC-1305 - */ - TimeStamp getOriginateTimeStamp(); - - /** - * @return poll interval as defined in RFC-1305. - * Field range between NTP_MINPOLL and NTP_MAXPOLL. - */ - int getPoll(); - - /** - * @return precision as defined in RFC-1305 - */ - int getPrecision(); - - /** - * @return the receive time as defined in RFC-1305 - */ - TimeStamp getReceiveTimeStamp(); - - /** - * @return the reference id (32-bit code) as defined in RFC-1305 - */ - int getReferenceId(); - - /** - * @return the reference id string - */ - String getReferenceIdString(); - - /** - * @return the reference time as defined in RFC-1305 - */ - TimeStamp getReferenceTimeStamp(); - - /** - * @return root delay as defined in RFC-1305 - */ - int getRootDelay(); - - /** - * @return root delay in milliseconds - */ - double getRootDelayInMillisDouble(); - - /** - * @return root dispersion as defined in RFC-1305 - */ - int getRootDispersion(); - - /** - * @return root dispersion in milliseconds - */ - long getRootDispersionInMillis(); - - /** - * @return root dispersion in milliseconds - */ - double getRootDispersionInMillisDouble(); - - /** - * @return stratum as defined in RFC-1305 - */ - int getStratum(); - - /** - * @return the transmit timestamp as defined in RFC-1305 - */ - TimeStamp getTransmitTimeStamp(); - - /** - * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) - * correspond to the protocol used to obtain the timing information. - * - * @return packet type string identifier - */ - String getType(); - - /** - * @return version as defined in RFC-1305 - */ - int getVersion(); - - /** - * Set the contents of this object from the datagram packet - * @param dp the packet - */ - void setDatagramPacket(DatagramPacket dp); - - /** - * Set leap indicator. - * @param li - leap indicator code - */ - void setLeapIndicator(int li); - - /** - * Set mode as defined in RFC-1305 - * @param mode the mode to set - */ - void setMode(int mode); - - /** - * Set originate timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - void setOriginateTimeStamp(TimeStamp ts); - - /** - * Set poll interval as defined in RFC-1305. - * Field range between NTP_MINPOLL and NTP_MAXPOLL. - * @param poll the interval to set - */ - void setPoll(int poll); - - /** - * Set precision as defined in RFC-1305 - * @param precision Precision - * @since 3.4 - */ - void setPrecision(int precision); - - /** - * Set receive timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - void setReceiveTimeStamp(TimeStamp ts); - - /** - * Set reference clock identifier field. - * @param refId the clock id field to set - */ - void setReferenceId(int refId); - - /** - * Set the reference timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - void setReferenceTime(TimeStamp ts); - - /** - * Set root delay as defined in RFC-1305 - * @param delay the delay to set - * @since 3.4 - */ - void setRootDelay(int delay); - - /** - * - * @param dispersion the value to set - * @since 3.4 - */ - void setRootDispersion(int dispersion); - - /** - * Set stratum as defined in RFC-1305 - * @param stratum the stratum to set - */ - void setStratum(int stratum); - - /** - * Set the transmit timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - void setTransmitTime(TimeStamp ts); - - /** - * Set version as defined in RFC-1305 - * @param version the version to set - */ - void setVersion(int version); - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ntp; + +import java.net.DatagramPacket; + +/** + * Interface for a NtpV3Packet with get/set methods corresponding to the fields + * in the NTP Data Message Header described in RFC 1305. + * + */ +public interface NtpV3Packet +{ + + /** + * Standard NTP UDP port + */ + int NTP_PORT = 123; + + int LI_NO_WARNING = 0; + int LI_LAST_MINUTE_HAS_61_SECONDS = 1; + int LI_LAST_MINUTE_HAS_59_SECONDS = 2; + int LI_ALARM_CONDITION = 3; + + /* mode options */ + int MODE_RESERVED = 0; + int MODE_SYMMETRIC_ACTIVE = 1; + int MODE_SYMMETRIC_PASSIVE = 2; + int MODE_CLIENT = 3; + int MODE_SERVER = 4; + int MODE_BROADCAST = 5; + int MODE_CONTROL_MESSAGE = 6; + int MODE_PRIVATE = 7; + + int NTP_MINPOLL = 4; // 16 seconds + int NTP_MAXPOLL = 14; // 16284 seconds + + int NTP_MINCLOCK = 1; + int NTP_MAXCLOCK = 10; + + int VERSION_3 = 3; + int VERSION_4 = 4; + + /* possible getType values such that other time-related protocols can + * have its information represented as NTP packets + */ + String TYPE_NTP = "NTP"; // RFC-1305/2030 + String TYPE_ICMP = "ICMP"; // RFC-792 + String TYPE_TIME = "TIME"; // RFC-868 + String TYPE_DAYTIME = "DAYTIME"; // RFC-867 + + /** + * @return a datagram packet with the NTP parts already filled in + */ + DatagramPacket getDatagramPacket(); + + /** + * @return leap indicator as defined in RFC-1305 + */ + int getLeapIndicator(); + + /** + * @return mode as defined in RFC-1305 + */ + int getMode(); + + /** + * @return mode as human readable string; e.g. 3=Client + */ + String getModeName(); + + /** + * @return the originate time as defined in RFC-1305 + */ + TimeStamp getOriginateTimeStamp(); + + /** + * @return poll interval as defined in RFC-1305. + * Field range between NTP_MINPOLL and NTP_MAXPOLL. + */ + int getPoll(); + + /** + * @return precision as defined in RFC-1305 + */ + int getPrecision(); + + /** + * @return the receive time as defined in RFC-1305 + */ + TimeStamp getReceiveTimeStamp(); + + /** + * @return the reference id (32-bit code) as defined in RFC-1305 + */ + int getReferenceId(); + + /** + * @return the reference id string + */ + String getReferenceIdString(); + + /** + * @return the reference time as defined in RFC-1305 + */ + TimeStamp getReferenceTimeStamp(); + + /** + * @return root delay as defined in RFC-1305 + */ + int getRootDelay(); + + /** + * @return root delay in milliseconds + */ + double getRootDelayInMillisDouble(); + + /** + * @return root dispersion as defined in RFC-1305 + */ + int getRootDispersion(); + + /** + * @return root dispersion in milliseconds + */ + long getRootDispersionInMillis(); + + /** + * @return root dispersion in milliseconds + */ + double getRootDispersionInMillisDouble(); + + /** + * @return stratum as defined in RFC-1305 + */ + int getStratum(); + + /** + * @return the transmit timestamp as defined in RFC-1305 + */ + TimeStamp getTransmitTimeStamp(); + + /** + * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) + * correspond to the protocol used to obtain the timing information. + * + * @return packet type string identifier + */ + String getType(); + + /** + * @return version as defined in RFC-1305 + */ + int getVersion(); + + /** + * Set the contents of this object from the datagram packet + * @param dp the packet + */ + void setDatagramPacket(DatagramPacket dp); + + /** + * Set leap indicator. + * @param li - leap indicator code + */ + void setLeapIndicator(int li); + + /** + * Set mode as defined in RFC-1305 + * @param mode the mode to set + */ + void setMode(int mode); + + /** + * Set originate timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + void setOriginateTimeStamp(TimeStamp ts); + + /** + * Set poll interval as defined in RFC-1305. + * Field range between NTP_MINPOLL and NTP_MAXPOLL. + * @param poll the interval to set + */ + void setPoll(int poll); + + /** + * Set precision as defined in RFC-1305 + * @param precision Precision + * @since 3.4 + */ + void setPrecision(int precision); + + /** + * Set receive timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + void setReceiveTimeStamp(TimeStamp ts); + + /** + * Set reference clock identifier field. + * @param refId the clock id field to set + */ + void setReferenceId(int refId); + + /** + * Set the reference timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + void setReferenceTime(TimeStamp ts); + + /** + * Set root delay as defined in RFC-1305 + * @param delay the delay to set + * @since 3.4 + */ + void setRootDelay(int delay); + + /** + * + * @param dispersion the value to set + * @since 3.4 + */ + void setRootDispersion(int dispersion); + + /** + * Set stratum as defined in RFC-1305 + * @param stratum the stratum to set + */ + void setStratum(int stratum); + + /** + * Set the transmit timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + void setTransmitTime(TimeStamp ts); + + /** + * Set version as defined in RFC-1305 + * @param version the version to set + */ + void setVersion(int version); + +} diff --git a/src/main/java/org/apache/commons/net/ntp/TimeInfo.java b/src/main/java/org/apache/commons/net/ntp/TimeInfo.java index c1234652..685419b5 100644 --- a/src/main/java/org/apache/commons/net/ntp/TimeInfo.java +++ b/src/main/java/org/apache/commons/net/ntp/TimeInfo.java @@ -1,343 +1,343 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.net.DatagramPacket; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; - -/** - * Wrapper class to network time packet messages (NTP, etc) that computes - * related timing info and stats. - */ -public class TimeInfo { - - private final NtpV3Packet message; - private List<String> comments; - private Long delayMillis; - private Long offsetMillis; - - /** - * time at which time message packet was received by local machine - */ - private final long returnTimeMillis; - - /** - * flag indicating that the TimeInfo details was processed and delay/offset were computed - */ - private boolean detailsComputed; - - /** - * Create TimeInfo object with raw packet message and destination time received. - * - * @param message NTP message packet - * @param returnTimeMillis destination receive time - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(final NtpV3Packet message, final long returnTimeMillis) { - this(message, returnTimeMillis, null, true); - } - - /** - * Create TimeInfo object with raw packet message and destination time received. - * Auto-computes details if computeDetails flag set otherwise this is delayed - * until computeDetails() is called. Delayed computation is for fast - * intialization when sub-millisecond timing is needed. - * - * @param msgPacket NTP message packet - * @param returnTimeMillis destination receive time - * @param doComputeDetails flag to pre-compute delay/offset values - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(final NtpV3Packet msgPacket, final long returnTimeMillis, final boolean doComputeDetails) - { - this(msgPacket, returnTimeMillis, null, doComputeDetails); - } - - /** - * Create TimeInfo object with raw packet message and destination time received. - * - * @param message NTP message packet - * @param returnTimeMillis destination receive time - * @param comments List of errors/warnings identified during processing - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(final NtpV3Packet message, final long returnTimeMillis, final List<String> comments) - { - this(message, returnTimeMillis, comments, true); - } - - /** - * Create TimeInfo object with raw packet message and destination time received. - * Auto-computes details if computeDetails flag set otherwise this is delayed - * until computeDetails() is called. Delayed computation is for fast - * intialization when sub-millisecond timing is needed. - * - * @param message NTP message packet - * @param returnTimeMillis destination receive time - * @param comments list of comments used to store errors/warnings with message - * @param doComputeDetails flag to pre-compute delay/offset values - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(final NtpV3Packet message, final long returnTimeMillis, final List<String> comments, - final boolean doComputeDetails) - { - if (message == null) { - throw new IllegalArgumentException("message cannot be null"); - } - this.returnTimeMillis = returnTimeMillis; - this.message = message; - this.comments = comments; - if (doComputeDetails) { - computeDetails(); - } - } - - /** - * Add comment (error/warning) to list of comments associated - * with processing of NTP parameters. If comment list not create - * then one will be created. - * - * @param comment the comment - */ - public void addComment(final String comment) - { - if (comments == null) { - comments = new ArrayList<>(); - } - comments.add(comment); - } - - /** - * Compute and validate details of the NTP message packet. Computed - * fields include the offset and delay. - */ - public void computeDetails() - { - if (detailsComputed) { - return; // details already computed - do nothing - } - detailsComputed = true; - if (comments == null) { - comments = new ArrayList<>(); - } - - final TimeStamp origNtpTime = message.getOriginateTimeStamp(); - final long origTimeMillis = origNtpTime.getTime(); - - // Receive Time is time request received by server (t2) - final TimeStamp rcvNtpTime = message.getReceiveTimeStamp(); - final long rcvTimeMillis = rcvNtpTime.getTime(); - - // Transmit time is time reply sent by server (t3) - final TimeStamp xmitNtpTime = message.getTransmitTimeStamp(); - final long xmitTimeMillis = xmitNtpTime.getTime(); - - /* - * 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 (origNtpTime.ntpValue() == 0) - { - // without originate time cannot determine when packet went out - // might be via a broadcast NTP packet... - if (xmitNtpTime.ntpValue() != 0) - { - offsetMillis = Long.valueOf(xmitTimeMillis - returnTimeMillis); - comments.add("Error: zero orig time -- cannot compute delay"); - } else { - comments.add("Error: zero orig time -- cannot compute delay/offset"); - } - } else if (rcvNtpTime.ntpValue() == 0 || xmitNtpTime.ntpValue() == 0) { - comments.add("Warning: zero rcvNtpTime or xmitNtpTime"); - // assert destTime >= origTime since network delay cannot be negative - if (origTimeMillis > returnTimeMillis) { - comments.add("Error: OrigTime > DestRcvTime"); - } else { - // without receive or xmit time cannot figure out processing time - // so delay is simply the network travel time - delayMillis = Long.valueOf(returnTimeMillis - origTimeMillis); - } - // 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 (rcvNtpTime.ntpValue() != 0) - { - // xmitTime is 0 just use rcv time - offsetMillis = Long.valueOf(rcvTimeMillis - origTimeMillis); - } else if (xmitNtpTime.ntpValue() != 0) - { - // rcvTime is 0 just use xmitTime time - offsetMillis = Long.valueOf(xmitTimeMillis - returnTimeMillis); - } - } else - { - long delayValueMillis = returnTimeMillis - origTimeMillis; - // assert xmitTime >= rcvTime: difference typically < 1ms - if (xmitTimeMillis < rcvTimeMillis) - { - // server cannot send out a packet before receiving it... - comments.add("Error: xmitTime < rcvTime"); // time-travel not allowed - } else - { - // subtract processing time from round-trip network delay - final long deltaMillis = xmitTimeMillis - rcvTimeMillis; - // in normal cases the processing delta is less than - // the total roundtrip network travel time. - if (deltaMillis <= delayValueMillis) - { - delayValueMillis -= deltaMillis; // 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 (deltaMillis - delayValueMillis == 1) - { - // delayValue == 0 -> local clock saw no tick change but destination clock did - if (delayValueMillis != 0) - { - comments.add("Info: processing time > total network time by 1 ms -> assume zero delay"); - delayValueMillis = 0; - } - } else { - comments.add("Warning: processing time > total network time"); - } - } - delayMillis = Long.valueOf(delayValueMillis); - if (origTimeMillis > returnTimeMillis) { - comments.add("Error: OrigTime > DestRcvTime"); - } - - offsetMillis = Long.valueOf(((rcvTimeMillis - origTimeMillis) + (xmitTimeMillis - returnTimeMillis)) / 2); - } - } - - /** - * Compares this object against the specified object. - * The result is <code>true</code> if and only if the argument is - * not <code>null</code> and is a <code>TimeStamp</code> object that - * contains the same values as this object. - * - * @param obj the object to compare with. - * @return <code>true</code> if the objects are the same; - * <code>false</code> otherwise. - * @since 3.4 - */ - @Override - public boolean equals(final Object obj) - { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final TimeInfo other = (TimeInfo) obj; - return returnTimeMillis == other.returnTimeMillis && message.equals(other.message); - } - - /** - * Get host address from message datagram if available - * @return host address of available otherwise null - * @since 3.4 - */ - public InetAddress getAddress() { - final DatagramPacket pkt = message.getDatagramPacket(); - return pkt == null ? null : pkt.getAddress(); - } - - /** - * Return list of comments (if any) during processing of NTP packet. - * - * @return List or null if not yet computed - */ - public List<String> getComments() - { - return comments; - } - - /** - * Get round-trip network delay. If null then could not compute the delay. - * - * @return Long or null if delay not available. - */ - public Long getDelay() - { - return delayMillis; - } - - /** - * Returns NTP message packet. - * - * @return NTP message packet. - */ - public NtpV3Packet getMessage() - { - return message; - } - - /** - * Get clock offset needed to adjust local clock to match remote clock. If null then could not - * compute the offset. - * - * @return Long or null if offset not available. - */ - public Long getOffset() - { - return offsetMillis; - } - - /** - * Returns time at which time message packet was received by local machine. - * - * @return packet return time. - */ - public long getReturnTime() - { - return returnTimeMillis; - } - - /** - * Computes a hashcode for this object. The result is the exclusive - * OR of the return time and the message hash code. - * - * @return a hash code value for this object. - * @since 3.4 - */ - @Override - public int hashCode() - { - final int prime = 31; - int result = (int)returnTimeMillis; - result = prime * result + message.hashCode(); - return result; - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ntp; + +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +/** + * Wrapper class to network time packet messages (NTP, etc) that computes + * related timing info and stats. + */ +public class TimeInfo { + + private final NtpV3Packet message; + private List<String> comments; + private Long delayMillis; + private Long offsetMillis; + + /** + * time at which time message packet was received by local machine + */ + private final long returnTimeMillis; + + /** + * flag indicating that the TimeInfo details was processed and delay/offset were computed + */ + private boolean detailsComputed; + + /** + * Create TimeInfo object with raw packet message and destination time received. + * + * @param message NTP message packet + * @param returnTimeMillis destination receive time + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(final NtpV3Packet message, final long returnTimeMillis) { + this(message, returnTimeMillis, null, true); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * Auto-computes details if computeDetails flag set otherwise this is delayed + * until computeDetails() is called. Delayed computation is for fast + * intialization when sub-millisecond timing is needed. + * + * @param msgPacket NTP message packet + * @param returnTimeMillis destination receive time + * @param doComputeDetails flag to pre-compute delay/offset values + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(final NtpV3Packet msgPacket, final long returnTimeMillis, final boolean doComputeDetails) + { + this(msgPacket, returnTimeMillis, null, doComputeDetails); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * + * @param message NTP message packet + * @param returnTimeMillis destination receive time + * @param comments List of errors/warnings identified during processing + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(final NtpV3Packet message, final long returnTimeMillis, final List<String> comments) + { + this(message, returnTimeMillis, comments, true); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * Auto-computes details if computeDetails flag set otherwise this is delayed + * until computeDetails() is called. Delayed computation is for fast + * intialization when sub-millisecond timing is needed. + * + * @param message NTP message packet + * @param returnTimeMillis destination receive time + * @param comments list of comments used to store errors/warnings with message + * @param doComputeDetails flag to pre-compute delay/offset values + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(final NtpV3Packet message, final long returnTimeMillis, final List<String> comments, + final boolean doComputeDetails) + { + if (message == null) { + throw new IllegalArgumentException("message cannot be null"); + } + this.returnTimeMillis = returnTimeMillis; + this.message = message; + this.comments = comments; + if (doComputeDetails) { + computeDetails(); + } + } + + /** + * Add comment (error/warning) to list of comments associated + * with processing of NTP parameters. If comment list not create + * then one will be created. + * + * @param comment the comment + */ + public void addComment(final String comment) + { + if (comments == null) { + comments = new ArrayList<>(); + } + comments.add(comment); + } + + /** + * Compute and validate details of the NTP message packet. Computed + * fields include the offset and delay. + */ + public void computeDetails() + { + if (detailsComputed) { + return; // details already computed - do nothing + } + detailsComputed = true; + if (comments == null) { + comments = new ArrayList<>(); + } + + final TimeStamp origNtpTime = message.getOriginateTimeStamp(); + final long origTimeMillis = origNtpTime.getTime(); + + // Receive Time is time request received by server (t2) + final TimeStamp rcvNtpTime = message.getReceiveTimeStamp(); + final long rcvTimeMillis = rcvNtpTime.getTime(); + + // Transmit time is time reply sent by server (t3) + final TimeStamp xmitNtpTime = message.getTransmitTimeStamp(); + final long xmitTimeMillis = xmitNtpTime.getTime(); + + /* + * 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 (origNtpTime.ntpValue() == 0) + { + // without originate time cannot determine when packet went out + // might be via a broadcast NTP packet... + if (xmitNtpTime.ntpValue() != 0) + { + offsetMillis = Long.valueOf(xmitTimeMillis - returnTimeMillis); + comments.add("Error: zero orig time -- cannot compute delay"); + } else { + comments.add("Error: zero orig time -- cannot compute delay/offset"); + } + } else if (rcvNtpTime.ntpValue() == 0 || xmitNtpTime.ntpValue() == 0) { + comments.add("Warning: zero rcvNtpTime or xmitNtpTime"); + // assert destTime >= origTime since network delay cannot be negative + if (origTimeMillis > returnTimeMillis) { + comments.add("Error: OrigTime > DestRcvTime"); + } else { + // without receive or xmit time cannot figure out processing time + // so delay is simply the network travel time + delayMillis = Long.valueOf(returnTimeMillis - origTimeMillis); + } + // 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 (rcvNtpTime.ntpValue() != 0) + { + // xmitTime is 0 just use rcv time + offsetMillis = Long.valueOf(rcvTimeMillis - origTimeMillis); + } else if (xmitNtpTime.ntpValue() != 0) + { + // rcvTime is 0 just use xmitTime time + offsetMillis = Long.valueOf(xmitTimeMillis - returnTimeMillis); + } + } else + { + long delayValueMillis = returnTimeMillis - origTimeMillis; + // assert xmitTime >= rcvTime: difference typically < 1ms + if (xmitTimeMillis < rcvTimeMillis) + { + // server cannot send out a packet before receiving it... + comments.add("Error: xmitTime < rcvTime"); // time-travel not allowed + } else + { + // subtract processing time from round-trip network delay + final long deltaMillis = xmitTimeMillis - rcvTimeMillis; + // in normal cases the processing delta is less than + // the total roundtrip network travel time. + if (deltaMillis <= delayValueMillis) + { + delayValueMillis -= deltaMillis; // 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 (deltaMillis - delayValueMillis == 1) + { + // delayValue == 0 -> local clock saw no tick change but destination clock did + if (delayValueMillis != 0) + { + comments.add("Info: processing time > total network time by 1 ms -> assume zero delay"); + delayValueMillis = 0; + } + } else { + comments.add("Warning: processing time > total network time"); + } + } + delayMillis = Long.valueOf(delayValueMillis); + if (origTimeMillis > returnTimeMillis) { + comments.add("Error: OrigTime > DestRcvTime"); + } + + offsetMillis = Long.valueOf(((rcvTimeMillis - origTimeMillis) + (xmitTimeMillis - returnTimeMillis)) / 2); + } + } + + /** + * Compares this object against the specified object. + * The result is <code>true</code> if and only if the argument is + * not <code>null</code> and is a <code>TimeStamp</code> object that + * contains the same values as this object. + * + * @param obj the object to compare with. + * @return <code>true</code> if the objects are the same; + * <code>false</code> otherwise. + * @since 3.4 + */ + @Override + public boolean equals(final Object obj) + { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final TimeInfo other = (TimeInfo) obj; + return returnTimeMillis == other.returnTimeMillis && message.equals(other.message); + } + + /** + * Get host address from message datagram if available + * @return host address of available otherwise null + * @since 3.4 + */ + public InetAddress getAddress() { + final DatagramPacket pkt = message.getDatagramPacket(); + return pkt == null ? null : pkt.getAddress(); + } + + /** + * Return list of comments (if any) during processing of NTP packet. + * + * @return List or null if not yet computed + */ + public List<String> getComments() + { + return comments; + } + + /** + * Get round-trip network delay. If null then could not compute the delay. + * + * @return Long or null if delay not available. + */ + public Long getDelay() + { + return delayMillis; + } + + /** + * Returns NTP message packet. + * + * @return NTP message packet. + */ + public NtpV3Packet getMessage() + { + return message; + } + + /** + * Get clock offset needed to adjust local clock to match remote clock. If null then could not + * compute the offset. + * + * @return Long or null if offset not available. + */ + public Long getOffset() + { + return offsetMillis; + } + + /** + * Returns time at which time message packet was received by local machine. + * + * @return packet return time. + */ + public long getReturnTime() + { + return returnTimeMillis; + } + + /** + * Computes a hashcode for this object. The result is the exclusive + * OR of the return time and the message hash code. + * + * @return a hash code value for this object. + * @since 3.4 + */ + @Override + public int hashCode() + { + final int prime = 31; + int result = (int)returnTimeMillis; + result = prime * result + message.hashCode(); + return result; + } + +} diff --git a/src/main/java/org/apache/commons/net/ntp/TimeStamp.java b/src/main/java/org/apache/commons/net/ntp/TimeStamp.java index f9aa8b95..5b247dd3 100644 --- a/src/main/java/org/apache/commons/net/ntp/TimeStamp.java +++ b/src/main/java/org/apache/commons/net/ntp/TimeStamp.java @@ -1,4 +1,3 @@ -package org.apache.commons.net.ntp; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -16,7 +15,7 @@ package org.apache.commons.net.ntp; * limitations under the License. */ - +package org.apache.commons.net.ntp; import java.io.IOException; import java.text.DateFormat; diff --git a/src/test/java/org/apache/commons/net/time/TimeTestSimpleServer.java b/src/test/java/org/apache/commons/net/time/TimeTestSimpleServer.java index e9b6780c..59777fb8 100644 --- a/src/test/java/org/apache/commons/net/time/TimeTestSimpleServer.java +++ b/src/test/java/org/apache/commons/net/time/TimeTestSimpleServer.java @@ -1,160 +1,160 @@ -package org.apache.commons.net.time; - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; - -/** - * The TimetSimpleServer class is a simple TCP implementation of a server - * for the Time Protocol described in RFC 868. - * <p> - * Listens for TCP socket connections on the time protocol port and writes - * the local time to socket outputStream as 32-bit integer of seconds - * since midnight on 1 January 1900 GMT. - * See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> for - * details. - * <p> - * Note this is for <B>debugging purposes only</B> and not meant to be run as a realiable time service. - * - */ -public class TimeTestSimpleServer implements Runnable -{ - - /** - * baseline time 1900-01-01T00:00:00 UTC - */ - public static final long SECONDS_1900_TO_1970 = 2208988800L; - - /** The default time port. It is set to 37 according to RFC 868. */ - public static final int DEFAULT_PORT = 37; - - public static void main(final String[] args) - { - final TimeTestSimpleServer server = new TimeTestSimpleServer(); - try - { - server.start(); - } catch (final IOException e) - { - // ignored - } - } - private ServerSocket server; - private final int port; - - private boolean running; - - public TimeTestSimpleServer() - { - port = DEFAULT_PORT; - } - - public TimeTestSimpleServer(final int port) - { - this.port = port; - } - - public void connect() throws IOException - { - if (server == null) - { - server = new ServerSocket(port); - } - } - - public int getPort() - { - return server == null ? port : server.getLocalPort(); - } - - public boolean isRunning() - { - return running; - } - - @Override - public void run() - { - Socket socket = null; - while (running) - { - try - { - socket = server.accept(); - final DataOutputStream os = new DataOutputStream(socket.getOutputStream()); - // add 500 ms to round off to nearest second - final int time = (int) ((System.currentTimeMillis() + 500) / 1000 + SECONDS_1900_TO_1970); - os.writeInt(time); - os.flush(); - } catch (final IOException e) - { - // ignored - } finally - { - if (socket != null) { - try - { - socket.close(); // force closing of the socket - } catch (final IOException e) - { - System.err.println("close socket error: " + e); - } - } - } - } - } - - /* - * Start time service and provide time to client connections. - */ - public void start() throws IOException - { - if (server == null) - { - connect(); - } - if (!running) - { - running = true; - new Thread(this).start(); - } - } - - /* - * Close server socket. - */ - public void stop() - { - running = false; - if (server != null) - { - try - { - server.close(); // force closing of the socket - } catch (final IOException e) - { - System.err.println("close socket error: " + e); - } - server = null; - } - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.time; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * The TimetSimpleServer class is a simple TCP implementation of a server + * for the Time Protocol described in RFC 868. + * <p> + * Listens for TCP socket connections on the time protocol port and writes + * the local time to socket outputStream as 32-bit integer of seconds + * since midnight on 1 January 1900 GMT. + * See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> for + * details. + * <p> + * Note this is for <B>debugging purposes only</B> and not meant to be run as a realiable time service. + * + */ +public class TimeTestSimpleServer implements Runnable +{ + + /** + * baseline time 1900-01-01T00:00:00 UTC + */ + public static final long SECONDS_1900_TO_1970 = 2208988800L; + + /** The default time port. It is set to 37 according to RFC 868. */ + public static final int DEFAULT_PORT = 37; + + public static void main(final String[] args) + { + final TimeTestSimpleServer server = new TimeTestSimpleServer(); + try + { + server.start(); + } catch (final IOException e) + { + // ignored + } + } + private ServerSocket server; + private final int port; + + private boolean running; + + public TimeTestSimpleServer() + { + port = DEFAULT_PORT; + } + + public TimeTestSimpleServer(final int port) + { + this.port = port; + } + + public void connect() throws IOException + { + if (server == null) + { + server = new ServerSocket(port); + } + } + + public int getPort() + { + return server == null ? port : server.getLocalPort(); + } + + public boolean isRunning() + { + return running; + } + + @Override + public void run() + { + Socket socket = null; + while (running) + { + try + { + socket = server.accept(); + final DataOutputStream os = new DataOutputStream(socket.getOutputStream()); + // add 500 ms to round off to nearest second + final int time = (int) ((System.currentTimeMillis() + 500) / 1000 + SECONDS_1900_TO_1970); + os.writeInt(time); + os.flush(); + } catch (final IOException e) + { + // ignored + } finally + { + if (socket != null) { + try + { + socket.close(); // force closing of the socket + } catch (final IOException e) + { + System.err.println("close socket error: " + e); + } + } + } + } + } + + /* + * Start time service and provide time to client connections. + */ + public void start() throws IOException + { + if (server == null) + { + connect(); + } + if (!running) + { + running = true; + new Thread(this).start(); + } + } + + /* + * Close server socket. + */ + public void stop() + { + running = false; + if (server != null) + { + try + { + server.close(); // force closing of the socket + } catch (final IOException e) + { + System.err.println("close socket error: " + e); + } + server = null; + } + } + +}