[P2play-commit] SF.net SVN: p2play: [13] trunk/P2Play/src/org/p2play/net
Status: Pre-Alpha
Brought to you by:
tisoft
|
From: <ti...@us...> - 2006-12-27 18:04:58
|
Revision: 13
http://p2play.svn.sourceforge.net/p2play/?rev=13&view=rev
Author: tisoft
Date: 2006-12-27 10:04:52 -0800 (Wed, 27 Dec 2006)
Log Message:
-----------
transfered from university cvs
added license header
changed package name to org.p2play.*
Added Paths:
-----------
trunk/P2Play/src/org/p2play/net/pastry/
trunk/P2Play/src/org/p2play/net/pastry/Pastry.java
trunk/P2Play/src/org/p2play/net/pastry/time/
trunk/P2Play/src/org/p2play/net/pastry/time/NTPMessage.java
trunk/P2Play/src/org/p2play/net/pastry/time/NTPTimeSource.java
trunk/P2Play/src/org/p2play/net/pastry/time/TimeManager.java
Added: trunk/P2Play/src/org/p2play/net/pastry/Pastry.java
===================================================================
--- trunk/P2Play/src/org/p2play/net/pastry/Pastry.java (rev 0)
+++ trunk/P2Play/src/org/p2play/net/pastry/Pastry.java 2006-12-27 18:04:52 UTC (rev 13)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2006 P2Play.org
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.p2play.net.pastry;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import org.p2play.net.pastry.time.NTPTimeSource;
+
+import rice.environment.Environment;
+import rice.environment.logging.LogManager;
+import rice.environment.params.simple.SimpleParameters;
+import rice.p2p.commonapi.Node;
+import rice.pastry.NodeIdFactory;
+import rice.pastry.PastryNode;
+import rice.pastry.socket.SocketPastryNodeFactory;
+import rice.pastry.standard.RandomNodeIdFactory;
+
+public class Pastry {
+ /**
+ * Boot into the Pastry Network
+ *
+ * @param remoteHost
+ * the remote host to boot into
+ * @param remotePort
+ * the port on the remote host to boot into
+ * @param externalHost
+ * our external IP
+ * @param localPort
+ * the port we bind to
+ * @return The local PastryNode, that is connected in the Pastry Network
+ * @throws IOException
+ */
+ public static Node boot(String remoteHost, int remotePort,
+ String externalHost, int localPort) throws IOException {
+ return boot(InetAddress.getByName(remoteHost), remotePort, InetAddress
+ .getByName(externalHost), localPort);
+ }
+
+ /**
+ * Boot into the Pastry Network
+ *
+ * @param remoteHost
+ * the remote host to boot into
+ * @param remotePort
+ * the port on the remote host to boot into
+ * @param externalHost
+ * our external IP
+ * @param localPort
+ * the port we bind to
+ * @return The local PastryNode, that is connected in the Pastry Network
+ * @throws IOException
+ */
+ public static Node boot(InetAddress remoteHost, int remotePort,
+ InetAddress externalHost, int localPort) throws IOException {
+ return boot(new InetSocketAddress(remoteHost, remotePort),
+ externalHost, localPort);
+ }
+ /**
+ * Boot into the Pastry Network
+ *
+ * @param remote
+ * the boot node
+ * @param externalAddress
+ * our external IP
+ * @param localPort
+ * the port we bind to
+ * @return The local PastryNode, that is connected in the Pastry Network
+ * @throws IOException
+ */
+ public static Node boot(InetSocketAddress remote,
+ InetAddress externalAddress, int localPort) throws IOException {
+ return boot(remote,externalAddress,localPort,null);
+ }
+
+
+ /**
+ * Boot into the Pastry Network
+ *
+ * @param remote
+ * the boot node
+ * @param externalAddress
+ * our external IP
+ * @param localPort
+ * the port we bind to
+ * @return The local PastryNode, that is connected in the Pastry Network
+ * @throws IOException
+ */
+ public static Node boot(InetSocketAddress remote,
+ InetAddress externalAddress, int localPort, LogManager logManager) throws IOException {
+ PastryNode node;
+
+ Environment environment = new Environment(null, null, null,
+ NTPTimeSource.getTimeSource(), logManager, new SimpleParameters(
+ new String[]{"mmog"}, null));
+ NodeIdFactory nidFactory = new RandomNodeIdFactory(environment);
+ SocketPastryNodeFactory factory = new SocketPastryNodeFactory(
+ nidFactory, externalAddress, localPort, environment, null);
+
+ node = factory.newNode(factory.getNodeHandle(remote));
+
+ while (!node.isReady()) {
+ // delay so we don't busy-wait
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ }
+ }
+
+ return node;
+ }
+}
Added: trunk/P2Play/src/org/p2play/net/pastry/time/NTPMessage.java
===================================================================
--- trunk/P2Play/src/org/p2play/net/pastry/time/NTPMessage.java (rev 0)
+++ trunk/P2Play/src/org/p2play/net/pastry/time/NTPMessage.java 2006-12-27 18:04:52 UTC (rev 13)
@@ -0,0 +1,473 @@
+package org.p2play.net.pastry.time;
+/*
+ * Copyright (c) 2004, Adam Buckley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Adam Buckley nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.p2play.util.NetRandom;
+
+
+/**
+ * This class represents a NTP message, as specified in RFC 2030. The message
+ * format is compatible with all versions of NTP and SNTP.
+ *
+ * This class does not support the optional authentication protocol, and
+ * ignores the key ID and message digest fields.
+ *
+ * For convenience, this class exposes message values as native Java types, not
+ * the NTP-specified data formats. For example, timestamps are
+ * stored as doubles (as opposed to the NTP unsigned 64-bit fixed point
+ * format).
+ *
+ * However, the contructor NtpMessage(byte[]) and the method toByteArray()
+ * allow the import and export of the raw NTP message format.
+ *
+ *
+ * Usage example
+ *
+ * // Send message
+ * DatagramSocket socket = new DatagramSocket();
+ * InetAddress address = InetAddress.getByName("ntp.cais.rnp.br");
+ * byte[] buf = new NtpMessage().toByteArray();
+ * DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 123);
+ * socket.send(packet);
+ *
+ * // Get response
+ * socket.receive(packet);
+ * System.out.println(msg.toString());
+ *
+ * Comments for member variables are taken from RFC2030 by David Mills,
+ * University of Delaware.
+ *
+ * Number format conversion code in NtpMessage(byte[] array) and toByteArray()
+ * inspired by http://www.pps.jussieu.fr/~jch/enseignement/reseaux/
+ * NTPMessage.java which is copyright (c) 2003 by Juliusz Chroboczek
+ *
+ * @author Adam Buckley
+ */
+public class NTPMessage {
+ private static NetRandom random=new NetRandom();
+
+ /**
+ * This is a two-bit code warning of an impending leap second to be
+ * inserted/deleted in the last minute of the current day. It's values
+ * may be as follows:
+ *
+ * Value Meaning
+ * ----- -------
+ * 0 no warning
+ * 1 last minute has 61 seconds
+ * 2 last minute has 59 seconds)
+ * 3 alarm condition (clock not synchronized)
+ */
+ public byte leapIndicator = 0;
+
+
+ /**
+ * This value indicates the NTP/SNTP version number. The version number
+ * is 3 for Version 3 (IPv4 only) and 4 for Version 4 (IPv4, IPv6 and OSI).
+ * If necessary to distinguish between IPv4, IPv6 and OSI, the
+ * encapsulating context must be inspected.
+ */
+ public byte version = 3;
+
+
+ /**
+ * This value indicates the mode, with values defined as follows:
+ *
+ * Mode Meaning
+ * ---- -------
+ * 0 reserved
+ * 1 symmetric active
+ * 2 symmetric passive
+ * 3 client
+ * 4 server
+ * 5 broadcast
+ * 6 reserved for NTP control message
+ * 7 reserved for private use
+ *
+ * In unicast and anycast modes, the client sets this field to 3 (client)
+ * in the request and the server sets it to 4 (server) in the reply. In
+ * multicast mode, the server sets this field to 5 (broadcast).
+ */
+ public byte mode = 0;
+
+
+ /**
+ * This value indicates the stratum level of the local clock, with values
+ * defined as follows:
+ *
+ * Stratum Meaning
+ * ----------------------------------------------
+ * 0 unspecified or unavailable
+ * 1 primary reference (e.g., radio clock)
+ * 2-15 secondary reference (via NTP or SNTP)
+ * 16-255 reserved
+ */
+ public short stratum = 0;
+
+
+ /**
+ * This value indicates the maximum interval between successive messages,
+ * in seconds to the nearest power of two. The values that can appear in
+ * this field presently range from 4 (16 s) to 14 (16284 s); however, most
+ * applications use only the sub-range 6 (64 s) to 10 (1024 s).
+ */
+ public byte pollInterval = 0;
+
+
+ /**
+ * This value indicates the precision of the local clock, in seconds to
+ * the nearest power of two. The values that normally appear in this field
+ * range from -6 for mains-frequency clocks to -20 for microsecond clocks
+ * found in some workstations.
+ */
+ public byte precision = 0;
+
+
+ /**
+ * This value indicates the total roundtrip delay to the primary reference
+ * source, in seconds. Note that this variable can take on both positive
+ * and negative values, depending on the relative time and frequency
+ * offsets. The values that normally appear in this field range from
+ * negative values of a few milliseconds to positive values of several
+ * hundred milliseconds.
+ */
+ public double rootDelay = 0;
+
+
+ /**
+ * This value indicates the nominal error relative to the primary reference
+ * source, in seconds. The values that normally appear in this field
+ * range from 0 to several hundred milliseconds.
+ */
+ public double rootDispersion = 0;
+
+
+ /**
+ * This is a 4-byte array identifying the particular reference source.
+ * In the case of NTP Version 3 or Version 4 stratum-0 (unspecified) or
+ * stratum-1 (primary) servers, this is a four-character ASCII string, left
+ * justified and zero padded to 32 bits. In NTP Version 3 secondary
+ * servers, this is the 32-bit IPv4 address of the reference source. In NTP
+ * Version 4 secondary servers, this is the low order 32 bits of the latest
+ * transmit timestamp of the reference source. NTP primary (stratum 1)
+ * servers should set this field to a code identifying the external
+ * reference source according to the following list. If the external
+ * reference is one of those listed, the associated code should be used.
+ * Codes for sources not listed can be contrived as appropriate.
+ *
+ * Code External Reference Source
+ * ---- -------------------------
+ * LOCL uncalibrated local clock used as a primary reference for
+ * a subnet without external means of synchronization
+ * PPS atomic clock or other pulse-per-second source
+ * individually calibrated to national standards
+ * ACTS NIST dialup modem service
+ * USNO USNO modem service
+ * PTB PTB (Germany) modem service
+ * TDF Allouis (France) Radio 164 kHz
+ * DCF Mainflingen (Germany) Radio 77.5 kHz
+ * MSF Rugby (UK) Radio 60 kHz
+ * WWV Ft. Collins (US) Radio 2.5, 5, 10, 15, 20 MHz
+ * WWVB Boulder (US) Radio 60 kHz
+ * WWVH Kaui Hawaii (US) Radio 2.5, 5, 10, 15 MHz
+ * CHU Ottawa (Canada) Radio 3330, 7335, 14670 kHz
+ * LORC LORAN-C radionavigation system
+ * OMEG OMEGA radionavigation system
+ * GPS Global Positioning Service
+ * GOES Geostationary Orbit Environment Satellite
+ */
+ public byte[] referenceIdentifier = {0, 0, 0, 0};
+
+
+ /**
+ * This is the time at which the local clock was last set or corrected, in
+ * seconds since 00:00 1-Jan-1900.
+ */
+ public double referenceTimestamp = 0;
+
+
+ /**
+ * This is the time at which the request departed the client for the
+ * server, in seconds since 00:00 1-Jan-1900.
+ */
+ public double originateTimestamp = 0;
+
+
+ /**
+ * This is the time at which the request arrived at the server, in seconds
+ * since 00:00 1-Jan-1900.
+ */
+ public double receiveTimestamp = 0;
+
+
+ /**
+ * This is the time at which the reply departed the server for the client,
+ * in seconds since 00:00 1-Jan-1900.
+ */
+ public double transmitTimestamp = 0;
+
+
+
+ /**
+ * Constructs a new NtpMessage from an array of bytes.
+ */
+ public NTPMessage(byte[] array) {
+ // See the packet format diagram in RFC 2030 for details
+ leapIndicator = (byte) ((array[0] >> 6) & 0x3);
+ version = (byte) ((array[0] >> 3) & 0x7);
+ mode = (byte) (array[0] & 0x7);
+ stratum = unsignedByteToShort(array[1]);
+ pollInterval = array[2];
+ precision = array[3];
+
+ rootDelay = (array[4] * 256.0) +
+ unsignedByteToShort(array[5]) +
+ (unsignedByteToShort(array[6]) / 256.0) +
+ (unsignedByteToShort(array[7]) / 65536.0);
+
+ rootDispersion = (unsignedByteToShort(array[8]) * 256.0) +
+ unsignedByteToShort(array[9]) +
+ (unsignedByteToShort(array[10]) / 256.0) +
+ (unsignedByteToShort(array[11]) / 65536.0);
+
+ referenceIdentifier[0] = array[12];
+ referenceIdentifier[1] = array[13];
+ referenceIdentifier[2] = array[14];
+ referenceIdentifier[3] = array[15];
+
+ referenceTimestamp = decodeTimestamp(array, 16);
+ originateTimestamp = decodeTimestamp(array, 24);
+ receiveTimestamp = decodeTimestamp(array, 32);
+ transmitTimestamp = decodeTimestamp(array, 40);
+ }
+
+
+
+ /**
+ * Constructs a new NtpMessage in client -> server mode, and sets the
+ * transmit timestamp to the current time.
+ */
+ public NTPMessage() {
+ // Note that all the other member variables are already set with
+ // appropriate default values.
+ this.mode = 3;
+ this.transmitTimestamp = (System.currentTimeMillis()/1000.0) + 2208988800.0;
+ }
+
+
+
+ /**
+ * This method constructs the data bytes of a raw NTP packet.
+ */
+ public byte[] toByteArray() {
+ // All bytes are automatically set to 0
+ byte[] p = new byte[48];
+
+ p[0] = (byte) (leapIndicator << 6 | version << 3 | mode);
+ p[1] = (byte) stratum;
+ p[2] = pollInterval;
+ p[3] = precision;
+
+ // root delay is a signed 16.16-bit FP, in Java an int is 32-bits
+ int l = (int) (rootDelay * 65536.0);
+ p[4] = (byte) ((l >> 24) & 0xFF);
+ p[5] = (byte) ((l >> 16) & 0xFF);
+ p[6] = (byte) ((l >> 8) & 0xFF);
+ p[7] = (byte) (l & 0xFF);
+
+ // root dispersion is an unsigned 16.16-bit FP, in Java there are no
+ // unsigned primitive types, so we use a long which is 64-bits
+ long ul = (long) (rootDispersion * 65536.0);
+ p[8] = (byte) ((ul >> 24) & 0xFF);
+ p[9] = (byte) ((ul >> 16) & 0xFF);
+ p[10] = (byte) ((ul >> 8) & 0xFF);
+ p[11] = (byte) (ul & 0xFF);
+
+ p[12] = referenceIdentifier[0];
+ p[13] = referenceIdentifier[1];
+ p[14] = referenceIdentifier[2];
+ p[15] = referenceIdentifier[3];
+
+ encodeTimestamp(p, 16, referenceTimestamp);
+ encodeTimestamp(p, 24, originateTimestamp);
+ encodeTimestamp(p, 32, receiveTimestamp);
+ encodeTimestamp(p, 40, transmitTimestamp);
+
+ return p;
+ }
+
+
+
+ /**
+ * Returns a string representation of a NtpMessage
+ */
+ @Override
+ public String toString() {
+ String precisionStr = new DecimalFormat("0.#E0").format(Math.pow(2, precision));
+
+ return "Leap indicator: " + leapIndicator + "\n" +
+ "Version: " + version + "\n" +
+ "Mode: " + mode + "\n" +
+ "Stratum: " + stratum + "\n" +
+ "Poll: " + pollInterval + "\n" +
+ "Precision: " + precision + " (" + precisionStr + " seconds)\n" +
+ "Root delay: " + new DecimalFormat("0.00").format(rootDelay*1000) + " ms\n" +
+ "Root dispersion: " + new DecimalFormat("0.00").format(rootDispersion*1000) + " ms\n" +
+ "Reference identifier: " + referenceIdentifierToString(referenceIdentifier, stratum, version) + "\n" +
+ "Reference timestamp: " + timestampToString(referenceTimestamp) + "\n" +
+ "Originate timestamp: " + timestampToString(originateTimestamp) + "\n" +
+ "Receive timestamp: " + timestampToString(receiveTimestamp) + "\n" +
+ "Transmit timestamp: " + timestampToString(transmitTimestamp);
+ }
+
+
+
+ /**
+ * Converts an unsigned byte to a short. By default, Java assumes that
+ * a byte is signed.
+ */
+ public static short unsignedByteToShort(byte b) {
+ if((b & 0x80)==0x80) {
+ return (short) (128 + (b & 0x7f));
+ } else {
+ return b;
+ }
+ }
+
+
+
+ /**
+ * Will read 8 bytes of a message beginning at <code>pointer</code>
+ * and return it as a double, according to the NTP 64-bit timestamp
+ * format.
+ */
+ public static double decodeTimestamp(byte[] array, int pointer) {
+ double r = 0.0;
+
+ for(int i=0; i<8; i++) {
+ r += unsignedByteToShort(array[pointer+i]) * Math.pow(2, (3-i)*8);
+ }
+
+ return r;
+ }
+
+
+
+ /**
+ * Encodes a timestamp in the specified position in the message
+ */
+ public static void encodeTimestamp(byte[] array, int pointer, double timestamp) {
+ // Converts a double into a 64-bit fixed point
+ for(int i=0; i<8; i++) {
+ // 2^24, 2^16, 2^8, .. 2^-32
+ double base = Math.pow(2, (3-i)*8);
+
+ // Capture byte value
+ array[pointer+i] = (byte) (timestamp / base);
+
+ // Subtract captured value from remaining total
+ timestamp -= (unsignedByteToShort(array[pointer+i]) * base);
+ }
+
+ // From RFC 2030: It is advisable to fill the non-significant
+ // low order bits of the timestamp with a random, unbiased
+ // bitstring, both to avoid systematic roundoff errors and as
+ // a means of loop detection and replay detection.
+ array[7+pointer] = (byte) (random.nextInt(255));
+ }
+
+
+
+ /**
+ * Returns a timestamp (number of seconds since 00:00 1-Jan-1900) as a
+ * formatted date/time string.
+ */
+ public static String timestampToString(double timestamp) {
+ if(timestamp==0) {
+ return "0";
+ }
+
+ // timestamp is relative to 1900, utc is used by Java and is relative
+ // to 1970
+ double utc = timestamp - (2208988800.0);
+
+ // milliseconds
+ long ms = (long) (utc * 1000.0);
+
+ // date/time
+ String date = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss").format(new Date(ms));
+
+ // fraction
+ double fraction = timestamp - ((long) timestamp);
+ String fractionSting = new DecimalFormat(".000000").format(fraction);
+
+ return date + fractionSting;
+ }
+
+
+
+ /**
+ * Returns a string representation of a reference identifier according
+ * to the rules set out in RFC 2030.
+ */
+ public static String referenceIdentifierToString(byte[] ref, short stratum, byte version) {
+ // From the RFC 2030:
+ // In the case of NTP Version 3 or Version 4 stratum-0 (unspecified)
+ // or stratum-1 (primary) servers, this is a four-character ASCII
+ // string, left justified and zero padded to 32 bits.
+ if(stratum==0 || stratum==1) {
+ return new String(ref);
+ }
+
+ // In NTP Version 3 secondary servers, this is the 32-bit IPv4
+ // address of the reference source.
+ else if(version==3) {
+ return unsignedByteToShort(ref[0]) + "." +
+ unsignedByteToShort(ref[1]) + "." +
+ unsignedByteToShort(ref[2]) + "." +
+ unsignedByteToShort(ref[3]);
+ }
+
+ // In NTP Version 4 secondary servers, this is the low order 32 bits
+ // of the latest transmit timestamp of the reference source.
+ else if(version==4) {
+ return "" + ((unsignedByteToShort(ref[0]) / 256.0) +
+ (unsignedByteToShort(ref[1]) / 65536.0) +
+ (unsignedByteToShort(ref[2]) / 16777216.0) +
+ (unsignedByteToShort(ref[3]) / 4294967296.0));
+ }
+
+ return "";
+ }
+}
Added: trunk/P2Play/src/org/p2play/net/pastry/time/NTPTimeSource.java
===================================================================
--- trunk/P2Play/src/org/p2play/net/pastry/time/NTPTimeSource.java (rev 0)
+++ trunk/P2Play/src/org/p2play/net/pastry/time/NTPTimeSource.java 2006-12-27 18:04:52 UTC (rev 13)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2006 P2Play.org
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.p2play.net.pastry.time;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import rice.environment.time.TimeSource;
+
+public class NTPTimeSource implements TimeSource, Runnable {
+
+ private static NTPTimeSource timeSource=new NTPTimeSource();
+
+ private NTPTimeSource() {
+ Thread t=new Thread(this);
+ t.setPriority(Thread.MIN_PRIORITY);
+ t.start();
+ }
+
+ private long currentOffset;
+
+ /** difference between the unix epoch and jan 1 1900 (NTP uses that) */
+ private final static double SECONDS_1900_TO_EPOCH = 2208988800.0;
+ private final static int NTP_PORT = 123;
+
+ private static final String[] NTP_SERVERS = {"ntp1.ptb.de"};
+
+ /**
+ * Query the ntp servers, returning the current time from first one we find
+ *
+ * @return milliseconds since january 1, 1970 (UTC)
+ * @throws IllegalArgumentException if none of the servers are reachable
+ */
+ private static long calculateCurrentOffset(String serverNames[]) {
+ if (serverNames == null) {
+ throw new IllegalArgumentException("No NTP servers specified");
+ }
+ ArrayList<String> names = new ArrayList<String>(serverNames.length);
+ for (String element : serverNames) {
+ names.add(element);
+ }
+ Collections.shuffle(names);
+ for (int i = 0; i < names.size(); i++) {
+ long now = calculateCurrentOffset(names.get(i));
+ if (now != Long.MIN_VALUE) {
+ return now;
+ }
+ }
+ throw new IllegalArgumentException("No reachable NTP servers specified");
+ }
+
+ /**
+ * Query the given NTP server, returning the current internet time
+ *
+ * @return milliseconds since january 1, 1970 (UTC), or -1 on error
+ */
+ private static long calculateCurrentOffset(String serverName) {
+ try {
+ // Send request
+ DatagramSocket socket = new DatagramSocket();
+ InetAddress address = InetAddress.getByName(serverName);
+ byte[] buf = new NTPMessage().toByteArray();
+ DatagramPacket packet = new DatagramPacket(buf, buf.length, address, NTP_PORT);
+
+ // Set the transmit timestamp *just* before sending the packet
+ // ToDo: Does this actually improve performance or not?
+ NTPMessage.encodeTimestamp(packet.getData(), 40,
+ (System.currentTimeMillis()/1000.0)
+ + SECONDS_1900_TO_EPOCH);
+
+ socket.send(packet);
+
+ // Get response
+ packet = new DatagramPacket(buf, buf.length);
+ socket.setSoTimeout(10*1000);
+ try {
+ socket.receive(packet);
+ } catch (InterruptedIOException iie) {
+ socket.close();
+ return -1;
+ }
+
+ // Immediately record the incoming timestamp
+ double destinationTimestamp = (System.currentTimeMillis()/1000.0) + SECONDS_1900_TO_EPOCH;
+
+ // Process response
+ NTPMessage msg = new NTPMessage(packet.getData());
+ /*double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
+ (msg.receiveTimestamp-msg.transmitTimestamp);*/
+ double localClockOffset = ((msg.receiveTimestamp - msg.originateTimestamp) +
+ (msg.transmitTimestamp - destinationTimestamp)) / 2;
+ socket.close();
+
+ long rv = (long)(localClockOffset*1000);
+ //System.out.println("host: " + address.getHostAddress() + " rtt: " + roundTripDelay + " offset: " + localClockOffset + " seconds");
+ return rv;
+ } catch (IOException ioe) {
+ //ioe.printStackTrace();
+ return Long.MIN_VALUE;
+ }
+ }
+
+
+ public long currentTimeMillis() {
+ return System.currentTimeMillis()+currentOffset;
+ }
+
+ public void run() {
+ while(true){
+ currentOffset=calculateCurrentOffset(NTP_SERVERS);
+
+ //System.out.println("current offset: "+currentOffset);
+
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static NTPTimeSource getTimeSource() {
+ return timeSource;
+ }
+
+ public void sleep(long delay) throws InterruptedException {
+ Thread.sleep(delay);
+ }
+
+}
Added: trunk/P2Play/src/org/p2play/net/pastry/time/TimeManager.java
===================================================================
--- trunk/P2Play/src/org/p2play/net/pastry/time/TimeManager.java (rev 0)
+++ trunk/P2Play/src/org/p2play/net/pastry/time/TimeManager.java 2006-12-27 18:04:52 UTC (rev 13)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2006 P2Play.org
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.p2play.net.pastry.time;
+
+import rice.p2p.commonapi.Node;
+
+public class TimeManager {
+ private static TimeManager timeManager;
+
+ private Node node;
+
+ private long baseTime=0;
+
+ private TimeManager(Node node) {
+ super();
+ this.node = node;
+ }
+
+ public static TimeManager getTimeManager() {
+ if(timeManager==null) {
+ throw new IllegalStateException("No TimeManager created. You have to call TimeManager.create() once before using it.");
+ }
+ return timeManager;
+ }
+
+ public static TimeManager create(Node node){
+ if(timeManager==null) {
+ timeManager=new TimeManager(node);
+ }
+
+ return timeManager;
+ }
+
+ public long getGameTime(){
+ return (baseTime+node.getEnvironment().getTimeSource().currentTimeMillis())/100L;
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|