package pt.jkaiui.ui.tools; import pt.jkaiui.JKaiUI; import java.net.*; import java.io.*; import pt.jkaiui.core.KaiConfig; /** * <p>Offers a static method for connecting to a remote NTP server, getting the * current time, and returning that as a java.util.Date object.</p> * * <p>This class is primarily used in the MainUI's toolbar to synchronize the time * to a correct, globally accurate settings</p> * * @author Jay */ public class NTPClient { /** This constructor is declared private to prevent instantation */ private NTPClient() {} /** * A static method to open a Socket to the default NTP server, retrieve the * time, and return that time in the form of a java.util.Date object. * * @return The current time based on a remote NTP server's time. */ public static long getNTPTime() { return getNTPTime(JKaiUI.getConfig().getConfigString(KaiConfig.ConfigTag.NTPSERVER)); } /** * A static method to open a Socket to a specified NTP server, retrieve the * time, and return that time in the form of a java.util.Date object. * * @param serverAddress the address to an NTP server * @return The current time based on a remote NTP server's time. */ public static long getNTPTime(String serverAddress) { Socket connection = null; try { // Try opening a Socket to the specified address on the NTP port connection = new Socket(serverAddress, 37); // If instantiating the Socket didn't throw an Exception, then we open // a BufferedInputStream to the server in preparation to read the data. BufferedInputStream bis = new BufferedInputStream(connection.getInputStream(), connection.getReceiveBufferSize()); // To make it more accurate, I have it check the current time before it // starts reading. This value will be used later to adjust the time // based on how long it actually took to get the time. long beforeTime = System.currentTimeMillis(); // Read a long datatype (split into four bytes) int b1 = bis.read(); int b2 = bis.read(); int b3 = bis.read(); int b4 = bis.read(); // Check the time after the four bytes are read. long afterTime = System.currentTimeMillis(); // Attempt to close the socket. If it doesn't close, oh well. :) try { if(connection != null) connection.close(); } catch(IOException ioe) { System.out.println("NTPClient:"+ioe); } // Check if any of the bytes were the EOF integer (-1) if((b1 | b2 | b3 | b4) < 0) throw new Exception("The time received was an invalid negative \"long\" number."); // Lastly, we multiply the time retrieved from the NTP server by 1000 // to convert it to milliseconds, add the delay it took to actually // get the time from the server, then return the new Date object. return (((((long) b1) << 24) + (b2 << 16) + (b3 << 8) + b4) * 1000) + (afterTime - beforeTime); } catch(Exception e) { // TODO: THIS SHOULD BE LOGGED, NOT PRINTED!!!! System.out.println("Failed to retrieve NTP time. Falling back to system time! Reason: " + e); return 0L; } } }