From 063284837c8c366e5502b1b0264b8eb807b61732 Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 14:21:09 +0100 Subject: Basic upload functionality to predifined location, with basic file browser --- org/apache/commons/net/ntp/NTPUDPClient.java | 140 +++++++ org/apache/commons/net/ntp/NtpUtils.java | 113 ++++++ org/apache/commons/net/ntp/NtpV3Impl.java | 583 +++++++++++++++++++++++++++ org/apache/commons/net/ntp/NtpV3Packet.java | 236 +++++++++++ org/apache/commons/net/ntp/TimeInfo.java | 295 ++++++++++++++ org/apache/commons/net/ntp/TimeStamp.java | 490 ++++++++++++++++++++++ 6 files changed, 1857 insertions(+) create mode 100644 org/apache/commons/net/ntp/NTPUDPClient.java create mode 100644 org/apache/commons/net/ntp/NtpUtils.java create mode 100644 org/apache/commons/net/ntp/NtpV3Impl.java create mode 100644 org/apache/commons/net/ntp/NtpV3Packet.java create mode 100644 org/apache/commons/net/ntp/TimeInfo.java create mode 100644 org/apache/commons/net/ntp/TimeStamp.java (limited to 'org/apache/commons/net/ntp') diff --git a/org/apache/commons/net/ntp/NTPUDPClient.java b/org/apache/commons/net/ntp/NTPUDPClient.java new file mode 100644 index 0000000..e1dcb57 --- /dev/null +++ b/org/apache/commons/net/ntp/NTPUDPClient.java @@ -0,0 +1,140 @@ +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 open + * and call getTime to retrieve the time. Then call + * close + * to close the connection properly. + * Successive calls to getTime are permitted + * without re-establishing a connection. That is because UDP is a + * connectionless protocol and the Network Time Protocol is stateless. + * + * @author Jason Mathews, MITRE Corp + * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ + ***/ + +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 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 TimeInfo + * object that allows access to all the fields of the NTP message header. + *

+ * @param host The address of the server. + * @param port The port of the service. + * @return The time value retrieved from the server. + * @exception IOException If an error occurs while retrieving the time. + ***/ + public TimeInfo getTime(InetAddress host, int port) throws IOException + { + // if not connected then open to next available UDP port + if (!isOpen()) + { + open(); + } + + NtpV3Packet message = new NtpV3Impl(); + message.setMode(NtpV3Packet.MODE_CLIENT); + message.setVersion(_version); + DatagramPacket sendPacket = message.getDatagramPacket(); + sendPacket.setAddress(host); + sendPacket.setPort(port); + + NtpV3Packet recMessage = new NtpV3Impl(); + 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 !!! + */ + 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); + + long returnTime = System.currentTimeMillis(); + // create TimeInfo message container but don't pre-compute the details yet + TimeInfo info = new TimeInfo(recMessage, returnTime, false); + + return info; + } + + /*** + * 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 TimeInfo + * object that allows access to all the fields of the NTP message header. + *

+ * @param host The address of the server. + * @return The time value retrieved from the server. + * @exception IOException If an error occurs while retrieving the time. + ***/ + public TimeInfo getTime(InetAddress host) throws IOException + { + return getTime(host, NtpV3Packet.NTP_PORT); + } + + /*** + * 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(int version) + { + _version = version; + } + +} diff --git a/org/apache/commons/net/ntp/NtpUtils.java b/org/apache/commons/net/ntp/NtpUtils.java new file mode 100644 index 0000000..ca1fb41 --- /dev/null +++ b/org/apache/commons/net/ntp/NtpUtils.java @@ -0,0 +1,113 @@ +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. + * + * @author Jason Mathews, MITRE Corp + * + * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ + */ +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(int address) + { + return ((address >>> 24) & 0xFF) + "." + + ((address >>> 16) & 0xFF) + "." + + ((address >>> 8) & 0xFF) + "." + + ((address >>> 0) & 0xFF); + } + + /*** + * 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(NtpV3Packet packet) + { + 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 Comprehensive + * List of Clock Drivers. + * + * @param message + * @return reference clock string if primary NTP server + */ + public static String getReferenceClock(NtpV3Packet message) { + if (message == null) + return ""; + int refId = message.getReferenceId(); + if (refId == 0) + return ""; + StringBuffer buf = new StringBuffer(4); + // start at highest-order byte (0x4c434c00 -> LCL) + for (int shiftBits = 24; shiftBits >= 0; shiftBits -= 8) + { + char c = (char) ((refId >>> shiftBits) & 0xff); + if (c == 0) break; // 0-terminated ASCII string + if (!Character.isLetterOrDigit(c)) + return ""; + buf.append(c); + } + return buf.toString(); + } + + /*** + * Return human-readable name of message mode type (RFC 1305). + * + * @param mode + * @return mode name + */ + public static String getModeName(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"; + } + } + +} diff --git a/org/apache/commons/net/ntp/NtpV3Impl.java b/org/apache/commons/net/ntp/NtpV3Impl.java new file mode 100644 index 0000000..4a8569a --- /dev/null +++ b/org/apache/commons/net/ntp/NtpV3Impl.java @@ -0,0 +1,583 @@ +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. + * + * @author Naz Irizarry, MITRE Corp + * @author Jason Mathews, MITRE Corp + * + * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ + */ +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 */ + + private byte[] buf = new byte[48]; + + private volatile DatagramPacket dp; + + /** Creates a new instance of NtpV3Impl */ + public NtpV3Impl() + { + } + + /*** + * 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. + */ + 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. + */ + public String getModeName() + { + return NtpUtils.getModeName(getMode()); + } + + /*** + * Set mode as defined in RFC-1305. + * @param mode + */ + public void setMode(int mode) + { + buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7); + } + + /*** + * 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. + */ + public int getLeapIndicator() + { + return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3; + } + + /*** + * Set leap indicator as defined in RFC-1305. + * @param li leap indicator. + */ + public void setLeapIndicator(int li) + { + buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT)); + } + + /*** + * 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. + */ + public int getPoll() + { + return buf[POLL_INDEX]; + } + + /*** + * Set poll interval as defined in RFC-1305. + * + * @param poll poll interval. + */ + public void setPoll(int poll) + { + buf[POLL_INDEX] = (byte) (poll & 0xFF); + } + + /*** + * 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. + */ + public int getPrecision() + { + return buf[PRECISION_INDEX]; + } + + /*** + * Set precision as defined in RFC-1305. + * @param precision + */ + public void setPrecision(int precision) + { + buf[PRECISION_INDEX] = (byte) (precision & 0xFF); + } + + /*** + * Returns NTP version number as defined in RFC-1305. + * + * @return NTP version number. + */ + public int getVersion() + { + return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7; + } + + /*** + * Set NTP version as defined in RFC-1305. + * + * @param version NTP version. + */ + public void setVersion(int version) + { + buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT)); + } + + /*** + * 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. + */ + public int getStratum() + { + return ui(buf[STRATUM_INDEX]); + } + + /*** + * Set stratum level as defined in RFC-1305. + * + * @param stratum stratum level. + */ + public void setStratum(int stratum) + { + buf[STRATUM_INDEX] = (byte) (stratum & 0xFF); + } + + /*** + * 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. + */ + 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 + */ + public double getRootDelayInMillisDouble() + { + double l = getRootDelay(); + return l / 65.536; + } + + /*** + * Returns root dispersion as defined in RFC-1305. + * @return root dispersion. + */ + public int getRootDispersion() + { + return getInt(ROOT_DISPERSION_INDEX); + } + + /*** + * Returns root dispersion (as defined in RFC-1305) in milliseconds. + * + * @return root dispersion in milliseconds + */ + public long getRootDispersionInMillis() + { + 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 + */ + public double getRootDispersionInMillisDouble() + { + double l = getRootDispersion(); + return l / 65.536; + } + + /*** + * Set reference clock identifier field with 32-bit unsigned integer value. + * See RFC-1305 for description. + * + * @param refId reference clock identifier. + */ + public void setReferenceId(int refId) + { + for (int i = 3; i >= 0; i--) { + buf[REFERENCE_ID_INDEX + i] = (byte) (refId & 0xff); + refId >>>= 8; // shift right one-byte + } + } + + /*** + * 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. + */ + 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. + */ + public String getReferenceIdString() + { + int version = getVersion(); + 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 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() + { + StringBuilder id = new StringBuilder(); + for (int i = 0; i <= 3; i++) { + char c = (char) buf[REFERENCE_ID_INDEX + i]; + if (c == 0) break; // 0-terminated string + id.append(c); + } + return id.toString(); + } + + private String idAsHex() + { + return Integer.toHexString(getReferenceId()); + } + + /*** + * Returns the transmit timestamp as defined in RFC-1305. + * + * @return the transmit timestamp as defined in RFC-1305. + * Never returns a null object. + */ + public TimeStamp getTransmitTimeStamp() + { + return getTimestamp(TRANSMIT_TIMESTAMP_INDEX); + } + + /*** + * Set transmit time with NTP timestamp. + * If ts is null then zero time is used. + * + * @param ts NTP timestamp + */ + public void setTransmitTime(TimeStamp ts) + { + setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts); + } + + /*** + * Set originate timestamp given NTP TimeStamp object. + * If ts is null then zero time is used. + * + * @param ts NTP timestamp + */ + public void setOriginateTimeStamp(TimeStamp ts) + { + setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts); + } + + /*** + * Returns the originate time as defined in RFC-1305. + * + * @return the originate time. + * Never returns null. + */ + public TimeStamp getOriginateTimeStamp() + { + return getTimestamp(ORIGINATE_TIMESTAMP_INDEX); + } + + /*** + * Returns the reference time as defined in RFC-1305. + * + * @return the reference time as TimeStamp object. + * Never returns null. + */ + public TimeStamp getReferenceTimeStamp() + { + return getTimestamp(REFERENCE_TIMESTAMP_INDEX); + } + + /*** + * Set Reference time with NTP timestamp. If ts is null + * then zero time is used. + * + * @param ts NTP timestamp + */ + public void setReferenceTime(TimeStamp ts) + { + setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts); + } + + /*** + * Returns receive timestamp as defined in RFC-1305. + * + * @return the receive time. + * Never returns null. + */ + public TimeStamp getReceiveTimeStamp() + { + return getTimestamp(RECEIVE_TIMESTAMP_INDEX); + } + + /*** + * Set receive timestamp given NTP TimeStamp object. + * If ts is null then zero time is used. + * + * @param ts timestamp + */ + public void setReceiveTimeStamp(TimeStamp ts) + { + setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts); + } + + /*** + * 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". + */ + public String getType() + { + return "NTP"; + } + + /*** + * @return 4 bytes as 32-bit int + */ + private int getInt(int index) + { + int i = ui(buf[index]) << 24 | + ui(buf[index + 1]) << 16 | + ui(buf[index + 2]) << 8 | + ui(buf[index + 3]); + + return i; + } + + /*** + * 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(int index) + { + return new TimeStamp(getLong(index)); + } + + /*** + * Get Long value represented by bits starting at specified index. + * + * @return 8 bytes as 64-bit long + */ + private long getLong(int index) + { + 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; + } + + /*** + * Sets the NTP timestamp at the given array index. + * + * @param index index into the byte array. + * @param t TimeStamp. + */ + private void setTimestamp(int index, 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.... + } + + /*** + * Returns the datagram packet with the NTP details already filled in. + * + * @return a datagram packet. + */ + public synchronized DatagramPacket getDatagramPacket() + { + if (dp == null) { + dp = new DatagramPacket(buf, buf.length); + dp.setPort(NTP_PORT); + } + return dp; + } + + /*** + * Set the contents of this object from source datagram packet. + * + * @param srcDp source DatagramPacket to copy contents from. + */ + public void setDatagramPacket(DatagramPacket srcDp) + { + byte[] incomingBuf = srcDp.getData(); + int len = srcDp.getLength(); + if (len > buf.length) + len = buf.length; + + System.arraycopy(incomingBuf, 0, buf, 0, len); + } + + /*** + * Convert byte to unsigned integer. + * Java only has signed types so we have to do + * more work to get unsigned ops. + * + * @param b + * @return unsigned int value of byte + */ + protected final static int ui(byte b) + { + 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 + * @return unsigned long value of byte + */ + protected final static long ul(byte b) + { + long i = b & 0xFF; + return i; + } + + /*** + * 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/org/apache/commons/net/ntp/NtpV3Packet.java b/org/apache/commons/net/ntp/NtpV3Packet.java new file mode 100644 index 0000000..52c828b --- /dev/null +++ b/org/apache/commons/net/ntp/NtpV3Packet.java @@ -0,0 +1,236 @@ +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. + * + * @author Naz Irizarry, MITRE Corp + * @author Jason Mathews, MITRE Corp + * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ + */ +public interface NtpV3Packet +{ + + /** + * Standard NTP UDP port + */ + public static final int NTP_PORT = 123; + + public static final int LI_NO_WARNING = 0; + public static final int LI_LAST_MINUTE_HAS_61_SECONDS = 1; + public static final int LI_LAST_MINUTE_HAS_59_SECONDS = 2; + public static final int LI_ALARM_CONDITION = 3; + + /* mode options */ + public static final int MODE_RESERVED = 0; + public static final int MODE_SYMMETRIC_ACTIVE = 1; + public static final int MODE_SYMMETRIC_PASSIVE = 2; + public static final int MODE_CLIENT = 3; + public static final int MODE_SERVER = 4; + public static final int MODE_BROADCAST = 5; + public static final int MODE_CONTROL_MESSAGE = 6; + public static final int MODE_PRIVATE = 7; + + public static final int NTP_MINPOLL = 4; // 16 seconds + public static final int NTP_MAXPOLL = 14; // 16284 seconds + + public static final int NTP_MINCLOCK = 1; + public static final int NTP_MAXCLOCK = 10; + + public static final int VERSION_3 = 3; + public static final int VERSION_4 = 4; + + /* possible getType values such that other time-related protocols can + * have its information represented as NTP packets + */ + public static final String TYPE_NTP = "NTP"; // RFC-1305/2030 + public static final String TYPE_ICMP = "ICMP"; // RFC-792 + public static final String TYPE_TIME = "TIME"; // RFC-868 + public static final String TYPE_DAYTIME = "DAYTIME"; // RFC-867 + + /** + * @return a datagram packet with the NTP parts already filled in + */ + public DatagramPacket getDatagramPacket(); + + /** + * Set the contents of this object from the datagram packet + */ + public void setDatagramPacket(DatagramPacket dp); + + /** + * @return leap indicator as defined in RFC-1305 + */ + public int getLeapIndicator(); + + /** + * Set leap indicator. + * @param li - leap indicator code + */ + public void setLeapIndicator(int li); + + /** + * @return mode as defined in RFC-1305 + */ + public int getMode(); + + /** + * @return mode as human readable string; e.g. 3=Client + */ + public String getModeName(); + + /** + * Set mode as defined in RFC-1305 + */ + public void setMode(int mode); + + /** + * @return poll interval as defined in RFC-1305. + * Field range between NTP_MINPOLL and NTP_MAXPOLL. + */ + public int getPoll(); + + /** + * Set poll interval as defined in RFC-1305. + * Field range between NTP_MINPOLL and NTP_MAXPOLL. + */ + public void setPoll(int poll); + + /** + * @return precision as defined in RFC-1305 + */ + public int getPrecision(); + + /** + * @return root delay as defined in RFC-1305 + */ + public int getRootDelay(); + + /** + * @return root delay in milliseconds + */ + public double getRootDelayInMillisDouble(); + + /** + * @return root dispersion as defined in RFC-1305 + */ + public int getRootDispersion(); + + /** + * @return root dispersion in milliseconds + */ + public long getRootDispersionInMillis(); + + /** + * @return root dispersion in milliseconds + */ + public double getRootDispersionInMillisDouble(); + + /** + * @return version as defined in RFC-1305 + */ + public int getVersion(); + + /** + * Set version as defined in RFC-1305 + */ + public void setVersion(int mode); + + /** + * @return stratum as defined in RFC-1305 + */ + public int getStratum(); + + /** + * Set stratum as defined in RFC-1305 + */ + public void setStratum(int stratum); + + /** + * @return the reference id string + */ + public String getReferenceIdString(); + + /** + * @return the reference id (32-bit code) as defined in RFC-1305 + */ + public int getReferenceId(); + + /** + * Set reference clock identifier field. + * @param refId + */ + public void setReferenceId(int refId); + + /** + * @return the transmit timestamp as defined in RFC-1305 + */ + public TimeStamp getTransmitTimeStamp(); + + /** + * @return the reference time as defined in RFC-1305 + */ + public TimeStamp getReferenceTimeStamp(); + + /** + * @return the originate time as defined in RFC-1305 + */ + public TimeStamp getOriginateTimeStamp(); + + /** + * @return the receive time as defined in RFC-1305 + */ + public TimeStamp getReceiveTimeStamp(); + + /** + * Set the transmit timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setTransmitTime(TimeStamp ts); + + /** + * Set the reference timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setReferenceTime(TimeStamp ts); + + /** + * Set originate timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setOriginateTimeStamp(TimeStamp ts); + + /** + * Set receive timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setReceiveTimeStamp(TimeStamp ts); + + /** + * 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 + */ + public String getType(); + +} diff --git a/org/apache/commons/net/ntp/TimeInfo.java b/org/apache/commons/net/ntp/TimeInfo.java new file mode 100644 index 0000000..4ef17fd --- /dev/null +++ b/org/apache/commons/net/ntp/TimeInfo.java @@ -0,0 +1,295 @@ +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.util.ArrayList; +import java.util.List; + +/** + * Wrapper class to network time packet messages (NTP, etc) that computes + * related timing info and stats. + * + * @author Jason Mathews, MITRE Corp + * + * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ + */ +public class TimeInfo { + + private NtpV3Packet _message; + private List _comments; + private Long _delay; + private Long _offset; + + /** + * time at which time message packet was received by local machine + */ + private long _returnTime; + + /** + * 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 returnTime destination receive time + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet message, long returnTime) { + this(message, returnTime, null, true); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * + * @param message NTP message packet + * @param returnTime destination receive time + * @param comments List of errors/warnings identified during processing + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet message, long returnTime, List comments) + { + this(message, returnTime, 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 msgPacket NTP message packet + * @param returnTime destination receive time + * @param doComputeDetails flag to pre-compute delay/offset values + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet msgPacket, long returnTime, boolean doComputeDetails) + { + this(msgPacket, returnTime, null, doComputeDetails); + } + + /** + * 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 returnTime 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(NtpV3Packet message, long returnTime, List comments, + boolean doComputeDetails) + { + if (message == null) + throw new IllegalArgumentException("message cannot be null"); + this._returnTime = returnTime; + 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 + */ + public void addComment(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(); + } + + TimeStamp origNtpTime = _message.getOriginateTimeStamp(); + long origTime = origNtpTime.getTime(); + + // Receive Time is time request received by server (t2) + TimeStamp rcvNtpTime = _message.getReceiveTimeStamp(); + long rcvTime = rcvNtpTime.getTime(); + + // Transmit time is time reply sent by server (t3) + TimeStamp xmitNtpTime = _message.getTransmitTimeStamp(); + long xmitTime = 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) + { + _offset = Long.valueOf(xmitTime - _returnTime); + _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 (origTime > _returnTime) + _comments.add("Error: OrigTime > DestRcvTime"); + else + { + // without receive or xmit time cannot figure out processing time + // so delay is simply the network travel time + _delay = Long.valueOf(_returnTime - origTime); + } + // 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 + _offset = Long.valueOf(rcvTime - origTime); + } else if (xmitNtpTime.ntpValue() != 0) + { + // rcvTime is 0 just use xmitTime time + _offset = Long.valueOf(xmitTime - _returnTime); + } + } else + { + long delayValue = _returnTime - origTime; + // assert xmitTime >= rcvTime: difference typically < 1ms + if (xmitTime < rcvTime) + { + // 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 + long delta = xmitTime - rcvTime; + // in normal cases the processing delta is less than + // the total roundtrip network travel time. + if (delta <= delayValue) + { + delayValue -= delta; // 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 (delta - delayValue == 1) + { + // delayValue == 0 -> local clock saw no tick change but destination clock did + if (delayValue != 0) + { + _comments.add("Info: processing time > total network time by 1 ms -> assume zero delay"); + delayValue = 0; + } + } else + _comments.add("Warning: processing time > total network time"); + } + } + _delay = Long.valueOf(delayValue); + if (origTime > _returnTime) // assert destTime >= origTime + _comments.add("Error: OrigTime > DestRcvTime"); + + _offset = Long.valueOf(((rcvTime - origTime) + (xmitTime - _returnTime)) / 2); + } + } + + /** + * Return list of comments (if any) during processing of NTP packet. + * + * @return List or null if not yet computed + */ + public List 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 _delay; + } + + /** + * 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 _offset; + } + + /** + * Returns NTP message packet. + * + * @return NTP message packet. + */ + public NtpV3Packet getMessage() + { + return _message; + } + + /** + * Returns time at which time message packet was received by local machine. + * + * @return packet return time. + */ + public long getReturnTime() + { + return _returnTime; + } + +} diff --git a/org/apache/commons/net/ntp/TimeStamp.java b/org/apache/commons/net/ntp/TimeStamp.java new file mode 100644 index 0000000..4cbe26f --- /dev/null +++ b/org/apache/commons/net/ntp/TimeStamp.java @@ -0,0 +1,490 @@ +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.lang.ref.SoftReference; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/*** + * TimeStamp class represents the Network Time Protocol (NTP) timestamp + * as defined in RFC-1305 and SNTP (RFC-2030). It is represented as a + * 64-bit unsigned fixed-point number in seconds relative to 0-hour on 1-January-1900. + * The 32-bit low-order bits are the fractional seconds whose precision is + * about 200 picoseconds. Assumes overflow date when date passes MAX_LONG + * and reverts back to 0 is 2036 and not 1900. Test for most significant + * bit: if MSB=0 then 2036 basis is used otherwise 1900 if MSB=1. + *

+ * Methods exist to convert NTP timestamps to and from the equivalent Java date + * representation, which is the number of milliseconds since the standard base + * time known as "the epoch", namely January 1, 1970, 00:00:00 GMT. + *

+ * + * @author Jason Mathews, MITRE Corp + * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ + * @see java.util.Date + */ +public class TimeStamp implements java.io.Serializable, Comparable // TODO add comparable type? +{ + + /** + * baseline NTP time if bit-0=0 -> 7-Feb-2036 @ 06:28:16 UTC + */ + protected static final long msb0baseTime = 2085978496000L; + + /** + * baseline NTP time if bit-0=1 -> 1-Jan-1900 @ 01:00:00 UTC + */ + protected static final long msb1baseTime = -2208988800000L; + + /** + * Default NTP date string format. E.g. Fri, Sep 12 2003 21:06:23.860. + * See java.text.SimpleDateFormat for code descriptions. + */ + public final static String NTP_DATE_FORMAT = "EEE, MMM dd yyyy HH:mm:ss.SSS"; + + /* + * Caches for the DateFormatters used by various toString methods. + */ + private static SoftReference simpleFormatter = null; + private static SoftReference utcFormatter = null; + + /** + * NTP timestamp value: 64-bit unsigned fixed-point number as defined in RFC-1305 + * with high-order 32 bits the seconds field and the low-order 32-bits the + * fractional field. + */ + private long ntpTime; + + private static final long serialVersionUID = 8139806907588338737L; + + // initialization of static time bases + /* + static { + TimeZone utcZone = TimeZone.getTimeZone("UTC"); + Calendar calendar = Calendar.getInstance(utcZone); + calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0); + calendar.set(Calendar.MILLISECOND, 0); + msb1baseTime = calendar.getTime().getTime(); + calendar.set(2036, Calendar.FEBRUARY, 7, 6, 28, 16); + calendar.set(Calendar.MILLISECOND, 0); + msb0baseTime = calendar.getTime().getTime(); + } + */ + + /*** + * Constructs a newly allocated NTP timestamp object + * that represents the native 64-bit long argument. + */ + public TimeStamp(long ntpTime) + { + this.ntpTime = ntpTime; + } + + /*** + * Constructs a newly allocated NTP timestamp object + * that represents the value represented by the string + * in hexdecimal form (e.g. "c1a089bd.fc904f6d"). + * + * @throws NumberFormatException - if the string does not contain a parsable timestamp. + */ + public TimeStamp(String s) throws NumberFormatException + { + ntpTime = decodeNtpHexString(s); + } + + /*** + * Constructs a newly allocated NTP timestamp object + * that represents the Java Date argument. + * + * @param d - the Date to be represented by the Timestamp object. + */ + public TimeStamp(Date d) + { + ntpTime = (d == null) ? 0 : toNtpTime(d.getTime()); + } + + /*** + * Returns the value of this Timestamp as a long value. + * + * @return the 64-bit long value represented by this object. + */ + public long ntpValue() + { + return ntpTime; + } + + /*** + * Returns high-order 32-bits representing the seconds of this NTP timestamp. + * + * @return seconds represented by this NTP timestamp. + */ + public long getSeconds() + { + return (ntpTime >>> 32) & 0xffffffffL; + } + + /*** + * Returns low-order 32-bits representing the fractional seconds. + * + * @return fractional seconds represented by this NTP timestamp. + */ + public long getFraction() + { + return ntpTime & 0xffffffffL; + } + + /*** + * Convert NTP timestamp to Java standard time. + * + * @return NTP Timestamp in Java time + */ + public long getTime() + { + return getTime(ntpTime); + } + + /*** + * Convert NTP timestamp to Java Date object. + * + * @return NTP Timestamp in Java Date + */ + public Date getDate() + { + long time = getTime(ntpTime); + return new Date(time); + } + + /*** + * Convert 64-bit NTP timestamp to Java standard time. + * + * Note that java time (milliseconds) by definition has less precision + * then NTP time (picoseconds) so converting NTP timestamp to java time and back + * to NTP timestamp loses precision. For example, Tue, Dec 17 2002 09:07:24.810 EST + * is represented by a single Java-based time value of f22cd1fc8a, but its + * NTP equivalent are all values ranging from c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c. + * + * @param ntpTimeValue + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT + * represented by this NTP timestamp value. + */ + public static long getTime(long ntpTimeValue) + { + long seconds = (ntpTimeValue >>> 32) & 0xffffffffL; // high-order 32-bits + long fraction = ntpTimeValue & 0xffffffffL; // low-order 32-bits + + // Use round-off on fractional part to preserve going to lower precision + fraction = Math.round(1000D * fraction / 0x100000000L); + + /* + * If the most significant bit (MSB) on the seconds field is set we use + * a different time base. The following text is a quote from RFC-2030 (SNTP v4): + * + * If bit 0 is set, the UTC time is in the range 1968-2036 and UTC time + * is reckoned from 0h 0m 0s UTC on 1 January 1900. If bit 0 is not set, + * the time is in the range 2036-2104 and UTC time is reckoned from + * 6h 28m 16s UTC on 7 February 2036. + */ + long msb = seconds & 0x80000000L; + if (msb == 0) { + // use base: 7-Feb-2036 @ 06:28:16 UTC + return msb0baseTime + (seconds * 1000) + fraction; + } else { + // use base: 1-Jan-1900 @ 01:00:00 UTC + return msb1baseTime + (seconds * 1000) + fraction; + } + } + + /*** + * Helper method to convert Java time to NTP timestamp object. + * Note that Java time (milliseconds) by definition has less precision + * then NTP time (picoseconds) so converting Ntptime to Javatime and back + * to Ntptime loses precision. For example, Tue, Dec 17 2002 09:07:24.810 + * is represented by a single Java-based time value of f22cd1fc8a, but its + * NTP equivalent are all values from c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c. + * @param date the milliseconds since January 1, 1970, 00:00:00 GMT. + * @return NTP timestamp object at the specified date. + */ + public static TimeStamp getNtpTime(long date) + { + return new TimeStamp(toNtpTime(date)); + } + + /*** + * Constructs a NTP timestamp object and initializes it so that + * it represents the time at which it was allocated, measured to the + * nearest millisecond. + * @return NTP timestamp object set to the current time. + * @see java.lang.System#currentTimeMillis() + */ + public static TimeStamp getCurrentTime() + { + return getNtpTime(System.currentTimeMillis()); + } + + /*** + * Convert NTP timestamp hexstring (e.g. "c1a089bd.fc904f6d") to the NTP + * 64-bit unsigned fixed-point number. + * + * @return NTP 64-bit timestamp value. + * @throws NumberFormatException - if the string does not contain a parsable timestamp. + */ + protected static long decodeNtpHexString(String s) + throws NumberFormatException + { + if (s == null) { + throw new NumberFormatException("null"); + } + int ind = s.indexOf('.'); + if (ind == -1) { + if (s.length() == 0) return 0; + return Long.parseLong(s, 16) << 32; // no decimal + } + + return Long.parseLong(s.substring(0, ind), 16) << 32 | + Long.parseLong(s.substring(ind + 1), 16); + } + + /*** + * Parses the string argument as a NTP hexidecimal timestamp representation string + * (e.g. "c1a089bd.fc904f6d"). + * + * @param s - hexstring. + * @return the Timestamp represented by the argument in hexidecimal. + * @throws NumberFormatException - if the string does not contain a parsable timestamp. + */ + public static TimeStamp parseNtpString(String s) + throws NumberFormatException + { + return new TimeStamp(decodeNtpHexString(s)); + } + + /*** + * Converts Java time to 64-bit NTP time representation. + * + * @param t Java time + * @return NTP timestamp representation of Java time value. + */ + protected static long toNtpTime(long t) + { + boolean useBase1 = t < msb0baseTime; // time < Feb-2036 + long baseTime; + if (useBase1) { + baseTime = t - msb1baseTime; // dates <= Feb-2036 + } else { + // if base0 needed for dates >= Feb-2036 + baseTime = t - msb0baseTime; + } + + long seconds = baseTime / 1000; + long fraction = ((baseTime % 1000) * 0x100000000L) / 1000; + + if (useBase1) { + seconds |= 0x80000000L; // set high-order bit if msb1baseTime 1900 used + } + + long time = seconds << 32 | fraction; + return time; + } + + /*** + * Computes a hashcode for this Timestamp. The result is the exclusive + * OR of the two halves of the primitive long value + * represented by this TimeStamp object. That is, the hashcode + * is the value of the expression: + *
+     * (int)(this.ntpValue()^(this.ntpValue() >>> 32))
+     * 
+ * + * @return a hash code value for this object. + */ + @Override + public int hashCode() + { + return (int) (ntpTime ^ (ntpTime >>> 32)); + } + + /*** + * Compares this object against the specified object. + * The result is true if and only if the argument is + * not null and is a Long object that + * contains the same long value as this object. + * + * @param obj the object to compare with. + * @return true if the objects are the same; + * false otherwise. + */ + @Override + public boolean equals(Object obj) + { + if (obj instanceof TimeStamp) { + return ntpTime == ((TimeStamp) obj).ntpValue(); + } + return false; + } + + /*** + * Converts this TimeStamp object to a String. + * The NTP timestamp 64-bit long value is represented as hex string with + * seconds separated by fractional seconds by a decimal point; + * e.g. c1a089bd.fc904f6d <=> Tue, Dec 10 2002 10:41:49.986 + * + * @return NTP timestamp 64-bit long value as hex string with seconds + * separated by fractional seconds. + */ + @Override + public String toString() + { + return toString(ntpTime); + } + + /*** + * Left-pad 8-character hex string with 0's + * + * @param buf - StringBuffer which is appended with leading 0's. + * @param l - a long. + */ + private static void appendHexString(StringBuffer buf, long l) + { + String s = Long.toHexString(l); + for (int i = s.length(); i < 8; i++) + buf.append('0'); + buf.append(s); + } + + /*** + * Converts 64-bit NTP timestamp value to a String. + * The NTP timestamp value is represented as hex string with + * seconds separated by fractional seconds by a decimal point; + * e.g. c1a089bd.fc904f6d <=> Tue, Dec 10 2002 10:41:49.986 + * + * @return NTP timestamp 64-bit long value as hex string with seconds + * separated by fractional seconds. + */ + public static String toString(long ntpTime) + { + StringBuffer buf = new StringBuffer(); + // high-order second bits (32..63) as hexstring + appendHexString(buf, (ntpTime >>> 32) & 0xffffffffL); + + // low-order fractional seconds bits (0..31) as hexstring + buf.append('.'); + appendHexString(buf, ntpTime & 0xffffffffL); + + return buf.toString(); + } + + /*** + * Converts this TimeStamp object to a String + * of the form: + *
+     * EEE, MMM dd yyyy HH:mm:ss.SSS
+ * See java.text.SimpleDataFormat for code descriptions. + * + * @return a string representation of this date. + */ + public String toDateString() + { + DateFormat formatter = null; + if (simpleFormatter != null) { + formatter = simpleFormatter.get(); + } + if (formatter == null) { + // No cache yet, or cached formatter GC'd + formatter = new SimpleDateFormat(NTP_DATE_FORMAT, Locale.US); + formatter.setTimeZone(TimeZone.getDefault()); + simpleFormatter = new SoftReference(formatter); + } + Date ntpDate = getDate(); + synchronized (formatter) { + return formatter.format(ntpDate); + } + } + + /*** + * Converts this TimeStamp object to a String + * of the form: + *
+     * EEE, MMM dd yyyy HH:mm:ss.SSS UTC
+ * See java.text.SimpleDataFormat for code descriptions. + * + * @return a string representation of this date in UTC. + */ + public String toUTCString() + { + DateFormat formatter = null; + if (utcFormatter != null) + formatter = utcFormatter.get(); + if (formatter == null) { + // No cache yet, or cached formatter GC'd + formatter = new SimpleDateFormat(NTP_DATE_FORMAT + " 'UTC'", + Locale.US); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + utcFormatter = new SoftReference(formatter); + } + Date ntpDate = getDate(); + synchronized (formatter) { + return formatter.format(ntpDate); + } + } + + /*** + * Compares two Timestamps numerically. + * + * @param anotherTimeStamp - the TimeStamp to be compared. + * @return the value 0 if the argument TimeStamp is equal to + * this TimeStamp; a value less than 0 if this TimeStamp + * is numerically less than the TimeStamp argument; and a + * value greater than 0 if this TimeStamp is + * numerically greater than the TimeStamp argument + * (signed comparison). + */ + public int compareTo(TimeStamp anotherTimeStamp) + { + long thisVal = this.ntpTime; + long anotherVal = anotherTimeStamp.ntpTime; + return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1)); + } + + /*** + * Compares this TimeStamp to another Object. If the Object is a TimeStamp, + * this function behaves like compareTo(TimeStamp). Otherwise, + * it throws a ClassCastException (as TimeStamps are comparable + * only to other TimeStamps). + * + * @param o the Object to be compared. + * @return the value 0 if the argument is a TimeStamp + * numerically equal to this TimeStamp; a value less than + * 0 if the argument is a TimeStamp numerically + * greater than this TimeStamp; and a value greater than + * 0 if the argument is a TimeStamp numerically + * less than this TimeStamp. + * @exception ClassCastException if the argument is not a + * TimeStamp. + * @see java.lang.Comparable + */ + public int compareTo(Object o) + { + return compareTo((TimeStamp) o); + } + +} -- cgit v1.2.3