Dépôt officiel du code source de l'ERP OpenConcerto
Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ntp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class SNTPClient {
protected final DatagramSocket socket;
/**
* The SNTP time is referenced to 01/01/1900-00:00. On the other hand, Unix systems and Java
* reference time to 01/01/1970-00:00. This means that convertion is necessary.
*/
private static final long SECS_1900_1970 = 2208988800L;
/**
* Constructor.
*
* @param timeout the response timeout (in milliseconds).
* @throws IllegalArgumentException if the timeout is invalid.
* @throws SocketException if an error occurs while creating the socket.
*/
public SNTPClient() throws SocketException {
this.socket = new DatagramSocket();
// 10s timeout
socket.setSoTimeout(10000);
}
/**
* Retrieves the network time offset from an SNTP server.
*
* @param host the server host address (IP or DNS).
* @param port the server port.
* @return the network time offset (in milliseconds).
*
* @throws IOException if an error occurs while contacting the server.
*/
public long getOffsetInMillis(final String host, final int port) throws IOException {
final InetAddress addr = InetAddress.getByName(host);
// Send
final Message smessage = new Message();
smessage.setTransmitTimestamp(toTimestamp(System.currentTimeMillis()));
final ByteArrayOutputStream output = new ByteArrayOutputStream();
smessage.encodeMessage(output);
final byte[] data = output.toByteArray();
output.close();
DatagramPacket rpacket = new DatagramPacket(data, data.length, addr, port);
socket.send(rpacket);
// Receive
final DatagramPacket packet = new DatagramPacket(new byte[Message.MAXIMUM_LENGTH], Message.MAXIMUM_LENGTH);
socket.receive(packet);
final long destinationTime = System.currentTimeMillis();
final Message rmessage = Message.decodeMessage(new ByteArrayInputStream(packet.getData()));
final long originalTime = fromTimestamp(rmessage.getOriginateTimestamp());
final long receiveTime = fromTimestamp(rmessage.getReceiveTimestamp());
final long transmitTime = fromTimestamp(rmessage.getTransmitTimestamp());
return ((receiveTime - originalTime) + (transmitTime - destinationTime)) / 2;
}
public void close() {
socket.close();
}
/**
* Converts Java time to an SNTP timestamp.
*
* @param time the Java time (in milliseconds).
* @return the SNTP timestamp.
*/
private static Timestamp toTimestamp(final long time) {
final double temp = ((double) time) / 1000D;
final long integer = (long) Math.floor(temp);
final long fraction = (long) ((temp - (double) integer) * 0x100000000L);
return new Timestamp(integer + SECS_1900_1970, fraction);
}
/**
* Converts an SNTP timestamp to Java time.
*
* @param timestamp the timestamp.
* @return the Java time (in milliseconds).
*/
private static final long fromTimestamp(final Timestamp timestamp) {
long time = (timestamp.getInteger() - SECS_1900_1970) * 1000L;
time += (timestamp.getFraction() * 1000L) / 0x100000000L;
return time;
}
public static void main(String[] args) throws IOException {
final SNTPClient client = new SNTPClient();
final long offset = client.getOffsetInMillis("fr.pool.ntp.org", 123);
client.close();
System.out.println(offset);
}
}