Pretty much done. A few bugs, check to see why we occasionally get a negative delay time. I suspect it's java reordering instructions... My clock seems to be ~35 seconds off of atomic time, which seems slightly high given that SNTP usually yields accuracy within 10's of milliseconds...

tmk29 [2002-12-11 19:45:33]
Pretty much done.  A few bugs, check to see why we occasionally get a negative delay time.  I suspect it's java reordering instructions...  My clock seems to be ~35 seconds off of atomic time, which seems slightly high given that SNTP usually yields accuracy within 10's of milliseconds...
Filename
meet-j/server/clocks/NTPTimeStamp.java
meet-j/server/clocks/SNTPClock.java
diff --git a/meet-j/server/clocks/NTPTimeStamp.java b/meet-j/server/clocks/NTPTimeStamp.java
index 2bb8cb3..fd0d3bf 100644
--- a/meet-j/server/clocks/NTPTimeStamp.java
+++ b/meet-j/server/clocks/NTPTimeStamp.java
@@ -3,10 +3,12 @@
  *
  * Created on December 6, 2002, 1:41 AM
  */
-package psl.meet.server.clocks;
+//package psl.meet.server.clocks;

 import java.util.BitSet;
 import java.util.Date;
+import java.math.BigInteger;
+import java.lang.Math;

 /**
  *
@@ -18,87 +20,151 @@ public class NTPTimeStamp {
     // milliseconds since Jan 1 1900 00:00:00 UT
     private long milli;

+    // seconds since Epoch
+    private long secs;
+
+    // fraction of a second
+    private float fracsecs;
+
+    // system offset, seconds between 1970 and 1900
+    //private long OFFSET = 2208970800;
+    //private final long OFFSET = 0;
+
+    private final BigInteger OFFSET = new BigInteger("2208970800");

     public NTPTimeStamp() {
 	Date now = new Date();
-	milli = now.getTime();;
+	secs = (long)(now.getTime() / 1000);
+	secs += OFFSET.longValue();
+
+	// parse into fracsecs
+	float foo = (float)(now.getTime() % 1000);
+	fracsecs = foo / 1000;
     }

+    public NTPTimeStamp(int tz) {
+	Date now = new Date();
+	secs = (long)(now.getTime() / 1000);
+	secs += OFFSET.longValue();
+	secs -= tz*3600;
+
+	// parse into fracsecs
+	float foo = (float)(now.getTime() % 1000);
+	fracsecs = foo / 1000;

-    public NTPTimeStamp(long time) {
-	milli = time;
     }


-    public NTPTimeStamp(byte[] b) {
+    // time == milliseconds since 1970
+    public NTPTimeStamp(long time, int tz) {
+	secs = (long)(time / 1000) + OFFSET.longValue() - (tz*3600);
+	float foo = (float)(time % 1000);
+	fracsecs = foo / 1000;
+    }

-	// parse the bytes to get a long
+    public NTPTimeStamp(Date now, int tz) {
+	long time = now.getTime();
+	secs = (long)(time / 1000) + OFFSET.longValue() - (tz*3600);
+
+	float foo = (float)(time % 1000);
+	fracsecs = foo / 1000;
     }


-    // take the milliseconds, return
-    // 8 bytes in NTP Timestamp format
-    // for use in Tx and Rx of NTP info
+    public NTPTimeStamp(byte[] b) {

-    public byte[] getBytes() {
+	// parse the bytes to get a long

-	long now = milli;
+	byte[] c = new byte[5];
+	c[0] = 0;
+	c[1] = b[0];
+	c[2] = b[1];
+	c[3] = b[2];
+	c[4] = b[3];

-        // convert msec to sec
-        int time1 = (int) now / 1000;
+	BigInteger bigint = new BigInteger(c);
+        secs = bigint.longValue();

-        // get remainder for 2nd part of timestamp
-        long time2 = now % 1000;
-        float foo = (float) time2 /  1000;
+	byte[] d = new byte[4];

-        BitSet bs = floatToFixedPoint(foo);
-        byte[] b2 = toByteArray(bs);
+	for (int i=0; i<4; i++) {
+	    d[i] = b[i+4];
+	}

-        byte[] b = new byte[8];
+	// parse last four bytes
+	fracsecs = bytesToFloat(d);
+    }

-        // in == long since Epoch
-        // must convert to NTP TimeStamp format
-        // first 32 bits = seconds since 1900 00:00:00 UT
-        // second 32 bits = fixed point fraction of a second
+    public long getSecs() {
+	return secs;
+    }
+
+    public float getFracSecs() {
+	return fracsecs;
+    }

-        b[0] = (byte)(time1 & 0xff);
-        b[1] = (byte)((time1 >> 8) & 0xff);
-        b[2] = (byte)((time1 >> 16) & 0xff);
-        b[3] = (byte)(time1 >>> 24);
+    public long getLong() {
+	long foo = (long)(1000 * fracsecs);

-        b[4] = b2[0];
-        b[5] = b2[1];
-        b[6] = b2[2];
-        b[7] = b2[3];
+	//System.out.println("secs = " + secs);
+	//System.out.println("fracsecs = " + fracsecs);

-	return b;
+	return (1000*secs + foo);
     }


-    // method to take byte array and
-    // calculate proper long
+    // take the seconds, return
+    // 8 bytes in NTP Timestamp format
+    // for use in Tx and Rx of NTP info

-    public static long NTPTimeStampToLong(byte[] b) {
+    public byte[] getBytes() {

-        int in = (b[0] & 0xff) | ((b[1] << 8) & 0xff00) | ((b[2] << 24) >>> 8) | (b[3] << 24);
-        return 0;
-    }
+	BigInteger bar = BigInteger.valueOf(secs);
+	byte[] b1 = bar.toByteArray();

+
+	if (b1.length > 4) {
+	    for (int i=0; i<4; i++) {
+		b1[i] = b1[i+1];
+	    }
+	}
+
+        BitSet bs = floatToFixedPoint(fracsecs);
+        byte[] b2 = toByteArray(bs);

+	byte[] output = new byte[8];

+	for (int i=0; i< 4; i++) {
+	    output[i] = b1[i];
+	    output[i+4] = b2[i];
+	}
+
+	return output;
+
+    }
+
+
+
     // Returns a bitset containing the values in bytes.
-    // The byte-ordering of bytes must be big-endian which means the most significant bit is in element 0.
+    // The byte-ordering of bytes must be big-endian which means
+    // the most significant bit is in element 0.
+
     public static BitSet fromByteArray(byte[] bytes) {
-	BitSet bits = new BitSet();
-	for (int i=0; i<bytes.length*8; i++) {
-	    if ((bytes[bytes.length-i/8-1]&(1<<(i%8))) > 0) {
-		bits.set(i);
+	BitSet bits = new BitSet(32);
+
+	for (int i=0; i<4; i++) {
+	    for (int j=0; j<8; j++) {
+		if ((bytes[4-i-1] & (1 << j)) > 0) {
+		    bits.set(8*i + j);
+		}
 	    }
 	}
+
 	return bits;
     }

-
+
+
     private static byte[] toByteArray(BitSet bits) {
         byte[] bytes = new byte[4];

@@ -114,6 +180,7 @@ public class NTPTimeStamp {
     }


+
     private static void printByteArray(byte[] b) {
         for (int i=0; i<b.length; i++) {
             System.out.print(b[i] + " ");
@@ -122,6 +189,23 @@ public class NTPTimeStamp {
     }


+    private static float bytesToFloat(byte[] b) {
+
+	float output = 0;
+
+	BitSet bs = fromByteArray(b);
+
+	for (int i=0; i<32; i++) {
+	    if (bs.get(i)) {
+		output += Math.pow(2,i-32);
+	    }
+	}
+
+	return output;
+
+    }
+
+
     private static BitSet floatToFixedPoint(float foo) {

         BitSet output = new BitSet(32);
@@ -145,14 +229,36 @@ public class NTPTimeStamp {

     public static void main(String args[]) throws Exception {

-	NTPTimeStamp now = new NTPTimeStamp();
+	Date nowDate = new Date();
+	System.out.println("Date:");
+	System.out.println(nowDate.getTime());

+	System.out.println("Test default constructor");
+	NTPTimeStamp now = new NTPTimeStamp();
 	printByteArray(now.getBytes());
-
-	Date epochcalc = new Date(0,0,1);
-
-	System.out.println(epochcalc);
-	System.out.println(epochcalc.getTime());
+	System.out.println(now.getLong());
+
+	System.out.println("Test byte[] constructor");
+
+	byte[] b = new byte[8];
+	b[0] = -125;
+	b[1] = -86;
+	b[2] = 56;
+	b[3] = 48;
+	b[4] = -128;
+	b[5] = 0;
+	b[6] = 0;
+	b[7] = 0;
+	NTPTimeStamp byteTest = new NTPTimeStamp(b);
+	printByteArray(byteTest.getBytes());
+	System.out.println(byteTest.getLong());
+
+	System.out.println("Test long constructor");
+
+	BigInteger BigOffset = new BigInteger("2208970800000");
+	NTPTimeStamp longTest = new NTPTimeStamp(BigOffset.longValue(),-5);
+	printByteArray(longTest.getBytes());
+	System.out.println(longTest.getLong());

     }

diff --git a/meet-j/server/clocks/SNTPClock.java b/meet-j/server/clocks/SNTPClock.java
index 2816ad0..8cec404 100644
--- a/meet-j/server/clocks/SNTPClock.java
+++ b/meet-j/server/clocks/SNTPClock.java
@@ -3,7 +3,7 @@
  *
  * Created on November 7, 2002, 8:34 PM
  */
-package psl.meet.server.clocks;
+


 import java.net.DatagramPacket;
@@ -19,73 +19,81 @@ import java.util.BitSet;
  */
 public class SNTPClock {

-    // multicast or unicast client
+    // multicast or unicast client, unused for now
     boolean multiCastMode;

     // offset from the system clock, this is updated
     // instead of actual system clock
     // (keep away from native methods for now)
-    long offset;
-
-    // built in offset
-    // most systems count from 1 Jan 1970
-    long sys_offset;
+    private long offset;

+    // roundtrip delay in communicating with NTP server
+    private long delay;

     // automatically update clock at certain intervals
-    long updateInterval;
+    private long updateInterval;

     // NTP Server to use
-    public String server;
-    public int port;
+    private String server;
+    private int port;

+    private int timezone = -5;

     /** Creates a new instance of SNTPClock */
     public SNTPClock() {
-	// number of milliseconds from 1970 to 1970
-	sys_offset = 2208970800000;
+	server = "";
+	port = 0;
+	timezone = 0;
+	updateInterval = -1;
+	delay = 0;
+	offset = 0;
     }

-
-    public SNTPClock(long s_offset) {
-	sys_offset = s_offset;
+    public SNTPClock(String srvr, int p, int tz, long updateint) {
+	server = srvr;
+	port = p;
+	timezone = tz;
+	updateInterval = updateint;
+	delay = 0;
+	offset = 0;
     }

-
-    public long getTime() {
-	Date now = new Date();
-        return now.getTime() + offset + sys_offset;
+    public void setTimezone(int tz) {
+	timezone = tz;
     }

+    public void setSource(String srvr, int p) {
+	server = srvr;
+	port = p;
+    }

-    // get time relative to the system time
-    // i.e. do not add the offset from 1970 -> 1900
-    public long getTimeRelSysTime() {
-	return now.getTime() + offset;
+    public void setUpdateInterval(long ui) {
+	updateInterval = ui;
     }

+    public long getTime() {
+	NTPTimeStamp now = new NTPTimeStamp(timezone);
+	return now.getLong() + offset;
+    }

     public long getOffset() {
 	return offset;
     }
-
-

-    public setSource(SourceDesc src) {
-
+    public long getDelay() {
+	return delay;
     }

+
+    public void sync() throws Exception {
+	byte[] b = this.createSNTPRequest();
+	this.send(b);
+    }

     public void send(byte[] data) throws Exception {

-        // create empty packet
-        //byte[] data = new byte[40];
-
-
         // create socket to server
         InetAddress address = InetAddress.getByName(server);
-	//printByteArray(address.getAddress());
-	//InetAddress address = InetAddress.getLocalHost();

         DatagramSocket socket = new DatagramSocket();
 	socket.connect(address,port);
@@ -102,26 +110,57 @@ public class SNTPClock {



-	byte[] rx = new byte[128];
-	packet = new DatagramPacket(rx,128);
+	byte[] rx = new byte[48];
+	packet = new DatagramPacket(rx,48);

 	//socket.disconnect();
 	//socket.close();


-        System.out.println("waiting for packet\n");
+        //System.out.println("waiting for packet\n");
         socket.receive(packet);
-
-        // print out what was received
-        //String msg = new String(packet.getData());

-        System.out.println("received: ");
-        printByteArray(packet.getData());
-
-
+        NTPTimeStamp T4 = new NTPTimeStamp(timezone);
+
+	byte[] t1 = new byte[8];
+	for (int i=0; i<8; i++) {
+	    t1[i] = rx[24+i];
+	}
+	NTPTimeStamp T1 = new NTPTimeStamp(t1);
+
+	byte[] t2 = new byte[8];
+	for (int i=0; i<8; i++) {
+	    t2[i] = rx[32+i];
+	}
+	NTPTimeStamp T2 = new NTPTimeStamp(t2);
+
+	byte[] t3 = new byte[8];
+	for (int i=0; i<8; i++) {
+	    t3[i] = rx[40+i];
+	}
+	NTPTimeStamp T3 = new NTPTimeStamp(t3);
+
+	// delay and offset, as defined in RFC 2030
+
+	delay = ( (T4.getLong() - T1.getLong()) - (T2.getLong() - T3.getLong()) );

-    }
+	offset = (long)(( (T2.getLong() - T1.getLong()) + (T3.getLong() - T4.getLong()) ) / 2);
+
+
+
+	//DEBUG
+	System.out.println("T1 = " + T1.getLong());
+	System.out.println("T2 = " + T2.getLong());
+	System.out.println("T3 = " + T3.getLong());
+	System.out.println("T4 = " + T4.getLong());
+
+	System.out.println("delay = " + delay);
+	System.out.println("offset = " + offset);

+    }
+
+
+    /// currently unused, could be useful for multi/anycast
     public void receive() throws Exception {

         //create empty packet
@@ -145,18 +184,12 @@ public class SNTPClock {
     }


-    public void syncTime() {
-
-    }
-
-
+    public byte[] createSNTPRequest() {

-
-
-    public static byte[] createSNTPRequest(byte[] time) {
+	NTPTimeStamp ntptime = new NTPTimeStamp(timezone);
+	byte[] time = ntptime.getBytes();

 	byte[] output = new byte[48];
-

 	for (int i=0; i < output.length; i++) {
 	    output[i] = 0;
@@ -176,6 +209,7 @@ public class SNTPClock {
     }


+    // DEBUG
     public static void printByteArray(byte[] b) {
         for (int i=0; i<b.length; i++) {
             System.out.print(b[i] + " ");
@@ -187,24 +221,12 @@ public class SNTPClock {

     public static void main(String args[]) throws Exception {

-	Date myDate = new Date();
-	long now = myDate.getTime();
-        byte[] b = longToNTPTimeStamp(now);
-        printByteArray(b);
+	SNTPClock sc = new SNTPClock(args[0], Integer.parseInt(args[1]), -5, 0);

-	System.out.println("");
-
-	byte[] b2 = createSNTPRequest(b);
-	printByteArray(b2);
-
-	SNTPClock sc = new SNTPClock();
-
-	sc.server = args[0];
-	sc.port = Integer.parseInt(args[1]);
-
-	sc.send(b2);
-
-	//sc.receive();
+	while (true) {
+	    sc.sync();
+	    Thread.sleep(1000);
+	}

     }