Ignore:
Timestamp:
09/17/11 15:19:05 (8 months ago)
Author:
delmitz
Branch:
default
Convert:
svn:7c3792e6-d75b-4784-96a6-b298f655ee64/trunk@2775
Message:

added NtpSyncService.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kraken-ntp/src/main/java/org/krakenapps/ntp/NtpClient.java

    r274 r341  
    1717 
    1818import java.io.IOException; 
     19import java.net.DatagramPacket; 
     20import java.net.DatagramSocket; 
    1921import java.net.InetAddress; 
     22import java.net.SocketTimeoutException; 
     23import java.net.UnknownHostException; 
     24import java.text.SimpleDateFormat; 
     25import java.util.Arrays; 
     26import java.util.Calendar; 
    2027import java.util.Date; 
     28 
     29import org.krakenapps.ntp.impl.ServerTime; 
     30import org.slf4j.Logger; 
     31import org.slf4j.LoggerFactory; 
    2132 
    2233/** 
    2334 * @author delmitz 
    2435 */ 
    25 public interface NtpClient { 
    26         InetAddress getTimeServer(); 
    27  
    28         int getTimeout(); 
    29  
    30         void setTimeServer(InetAddress server); 
    31  
    32         void setTimeout(int millisecond); 
    33  
    34         Date sync(); 
    35  
    36         void setSystemTime(Date date) throws IOException; 
     36public class NtpClient { 
     37        private static final String DEFAULT_TIME_SERVER = "pool.ntp.org"; 
     38        private static final int NTP_V3_PACKET = 3; 
     39        private static final int CLIENT_MODE = 3; 
     40        private static final int STRATUM_INDEX = 1; 
     41        private static final int POLL_INDEX = 2; 
     42        private static final int PRECISION_INDEX = 3; 
     43        private static final int ROOT_DELAY_INDEX = 4; 
     44        private static final int ROOT_DISPERSION_INDEX = 8; 
     45        private static final int REFERENCE_IDENTIFIER_INDEX = 12; 
     46        private static final int REFERENCE_TIMESTAMP_INDEX = 16; 
     47        private static final int ORIGINATE_TIMESTAMP_INDEX = 24; 
     48        private static final int RECEIVE_TIMESTAMP_INDEX = 32; 
     49        private static final int TRANSMIT_TIMESTAMP_INDEX = 40; 
     50 
     51        private Logger logger = LoggerFactory.getLogger(NtpClient.class); 
     52 
     53        private InetAddress timeServer; 
     54        private int timeout; 
     55 
     56        public NtpClient() throws UnknownHostException { 
     57                this(null); 
     58        } 
     59 
     60        public NtpClient(String timeServer) throws UnknownHostException { 
     61                this(timeServer, 5000); 
     62        } 
     63 
     64        public NtpClient(String timeServer, int timeout) throws UnknownHostException { 
     65                if (timeServer == null) 
     66                        timeServer = DEFAULT_TIME_SERVER; 
     67                this.timeServer = InetAddress.getByName(timeServer); 
     68                this.timeout = timeout; 
     69        } 
     70 
     71        public InetAddress getTimeServer() { 
     72                return timeServer; 
     73        } 
     74 
     75        public void setTimeServer(InetAddress timeServer) { 
     76                this.timeServer = timeServer; 
     77        } 
     78 
     79        public int getTimeout() { 
     80                return timeout; 
     81        } 
     82 
     83        public void setTimeout(int timeout) { 
     84                this.timeout = timeout; 
     85        } 
     86 
     87        public void setSystemTime(Date time) throws IOException { 
     88                String os = System.getProperty("os.name"); 
     89                if (os.contains("Windows")) { 
     90                        String newDate = new SimpleDateFormat("MM-dd-yy").format(time); 
     91                        Runtime.getRuntime().exec("cmd /c date " + newDate); 
     92 
     93                        String newTime = new SimpleDateFormat("HH:mm:ss.SSS").format(time); 
     94                        newTime = newTime.substring(0, newTime.length() - 1); 
     95                        Runtime.getRuntime().exec("cmd /c time " + newTime); 
     96                } else if (os.contains("Linux")) { 
     97                        String newTime = new SimpleDateFormat("MMddHHmmyyyy.ss").format(time); 
     98                        Runtime.getRuntime().exec("date " + newTime); 
     99                } else { 
     100                        // just pray 
     101                        String newTime = new SimpleDateFormat("MMddHHmmyyyy.ss").format(time); 
     102                        Runtime.getRuntime().exec("date " + newTime); 
     103                } 
     104        } 
     105 
     106        public Date sync() { 
     107                try { 
     108                        ServerTime time = getTime(); 
     109                        setSystemTime(addOffset(time)); 
     110                        logger.info("kraken ntp: The time has been successfully synchronized with {} on {}", timeServer, 
     111                                        new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS 'UTC'").format(time.getTransmit())); 
     112                        return time.getTransmit(); 
     113                } catch (SocketTimeoutException e) { 
     114                        logger.error("kraken ntp: receive timeout.", e); 
     115                } catch (IOException e) { 
     116                        logger.error("kraken ntp: sync failed.", e); 
     117                } 
     118 
     119                return null; 
     120        } 
     121 
     122        private ServerTime getTime() throws IOException { 
     123                DatagramSocket socket = new DatagramSocket(); 
     124                socket.setSoTimeout(timeout); 
     125                transmit(socket, timeServer, 123); 
     126                ServerTime time = receive(socket); 
     127                time.setDestination(getUtcTimeMillis()); 
     128                return time; 
     129        } 
     130 
     131        private void transmit(DatagramSocket socket, InetAddress addr, int port) throws IOException { 
     132                byte[] buf = new byte[48]; 
     133                buf[0] |= NTP_V3_PACKET; // set NTP Packet version 3 
     134                buf[0] |= (CLIENT_MODE << 3); // set Client mode 
     135 
     136                long now = getUtcTimeMillis(); 
     137                now += 2209021200000L; // baseline 1970 to 1900 
     138 
     139                long l = (now / 1000) << 32; 
     140                l |= ((now % 1000) << 32) / 1000; 
     141                for (int i = 7; i >= 0; i--) { // set Transmit Timestamp 
     142                        buf[TRANSMIT_TIMESTAMP_INDEX + i] = (byte) (l & 0xff); 
     143                        l >>>= 8; 
     144                } 
     145 
     146                DatagramPacket p = new DatagramPacket(buf, buf.length); 
     147                p.setAddress(addr); 
     148                p.setPort(port); 
     149                socket.send(p); 
     150        } 
     151 
     152        private long getUtcTimeMillis() { 
     153                return System.currentTimeMillis() - Calendar.getInstance().getTimeZone().getOffset(0); 
     154        } 
     155 
     156        private ServerTime receive(DatagramSocket socket) throws IOException, SocketTimeoutException { 
     157                byte[] buf = new byte[48]; 
     158                DatagramPacket p = new DatagramPacket(buf, buf.length); 
     159                socket.receive(p); 
     160 
     161                ServerTime time = new ServerTime(); 
     162                time.setStratum((int) buf[STRATUM_INDEX]); 
     163                time.setPoll(buf[POLL_INDEX]); 
     164                time.setPrecision(buf[PRECISION_INDEX]); 
     165                time.setRootDelay(Arrays.copyOfRange(buf, ROOT_DELAY_INDEX, ROOT_DELAY_INDEX + 4)); 
     166                time.setRootDispersion(Arrays.copyOfRange(buf, ROOT_DISPERSION_INDEX, ROOT_DISPERSION_INDEX + 4)); 
     167                time.setReferenceIdentifier(Arrays.copyOfRange(buf, REFERENCE_IDENTIFIER_INDEX, REFERENCE_IDENTIFIER_INDEX + 4)); 
     168                time.setReference(ntpTimeToJavaDate(buf, REFERENCE_TIMESTAMP_INDEX)); 
     169                time.setOriginate(ntpTimeToJavaDate(buf, ORIGINATE_TIMESTAMP_INDEX)); 
     170                time.setReceive(ntpTimeToJavaDate(buf, RECEIVE_TIMESTAMP_INDEX)); 
     171                time.setTransmit(ntpTimeToJavaDate(buf, TRANSMIT_TIMESTAMP_INDEX)); 
     172 
     173                return time; 
     174        } 
     175 
     176        private long ntpTimeToJavaDate(byte[] buf, int offset) { 
     177                long seconds = 0; 
     178                for (int i = 0; i < 4; i++) { 
     179                        seconds = seconds << 8; 
     180                        seconds |= buf[offset + i] & 0xff; 
     181                } 
     182                seconds *= 1000L; 
     183                seconds -= 2209021200000L; // baseline 1900 to 1970 
     184 
     185                long fraction = 0; 
     186                for (int i = 4; i < 8; i++) { 
     187                        fraction = fraction << 8; 
     188                        fraction |= buf[offset + i] & 0xff; 
     189                } 
     190                fraction *= 1000; 
     191                fraction >>>= 32; 
     192 
     193                return (seconds + fraction); 
     194        } 
     195 
     196        private Date addOffset(ServerTime time) { 
     197                long millis = System.currentTimeMillis() + time.getClockOffset(); 
     198                return new Date(millis); 
     199        } 
    37200} 
Note: See TracChangeset for help on using the changeset viewer.