FileDocCategorySizeDatePackage
SntpClient.javaAPI DocAndroid 5.1 API8070Thu Mar 12 22:22:10 GMT 2015android.net

SntpClient

public class SntpClient extends Object
{@hide} Simple SNTP client class for retrieving network time. Sample usage:
SntpClient client = new SntpClient();
if (client.requestTime("time.foo.com")) {
long now = client.getNtpTime() + SystemClock.elapsedRealtime() - client.getNtpTimeReference();
}

Fields Summary
private static final String
TAG
private static final int
REFERENCE_TIME_OFFSET
private static final int
ORIGINATE_TIME_OFFSET
private static final int
RECEIVE_TIME_OFFSET
private static final int
TRANSMIT_TIME_OFFSET
private static final int
NTP_PACKET_SIZE
private static final int
NTP_PORT
private static final int
NTP_MODE_CLIENT
private static final int
NTP_VERSION
private static final long
OFFSET_1900_TO_1970
private long
mNtpTime
private long
mNtpTimeReference
private long
mRoundTripTime
Constructors Summary
Methods Summary
public longgetNtpTime()
Returns the time computed from the NTP transaction.

return
time value computed from NTP server response.

        return mNtpTime;
    
public longgetNtpTimeReference()
Returns the reference clock value (value of SystemClock.elapsedRealtime()) corresponding to the NTP time.

return
reference clock corresponding to the NTP time.

        return mNtpTimeReference;
    
public longgetRoundTripTime()
Returns the round trip time of the NTP transaction

return
round trip time in milliseconds.

        return mRoundTripTime;
    
private longread32(byte[] buffer, int offset)
Reads an unsigned 32 bit big endian number from the given offset in the buffer.

        byte b0 = buffer[offset];
        byte b1 = buffer[offset+1];
        byte b2 = buffer[offset+2];
        byte b3 = buffer[offset+3];

        // convert signed bytes to unsigned values
        int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
        int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
        int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
        int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);

        return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
    
private longreadTimeStamp(byte[] buffer, int offset)
Reads the NTP time stamp at the given offset in the buffer and returns it as a system time (milliseconds since January 1, 1970).

        long seconds = read32(buffer, offset);
        long fraction = read32(buffer, offset + 4);
        return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);        
    
public booleanrequestTime(java.lang.String host, int timeout)
Sends an SNTP request to the given host and processes the response.

param
host host name of the server.
param
timeout network timeout in milliseconds.
return
true if the transaction was successful.


                                         
          
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket();
            socket.setSoTimeout(timeout);
            InetAddress address = InetAddress.getByName(host);
            byte[] buffer = new byte[NTP_PACKET_SIZE];
            DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);

            // set mode = 3 (client) and version = 3
            // mode is in low 3 bits of first byte
            // version is in bits 3-5 of first byte
            buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

            // get current time and write it to the request packet
            long requestTime = System.currentTimeMillis();
            long requestTicks = SystemClock.elapsedRealtime();
            writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);

            socket.send(request);

            // read the response
            DatagramPacket response = new DatagramPacket(buffer, buffer.length);
            socket.receive(response);
            long responseTicks = SystemClock.elapsedRealtime();
            long responseTime = requestTime + (responseTicks - requestTicks);

            // extract the results
            long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
            long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
            long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
            long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
            // receiveTime = originateTime + transit + skew
            // responseTime = transmitTime + transit - skew
            // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
            //             = ((originateTime + transit + skew - originateTime) +
            //                (transmitTime - (transmitTime + transit - skew)))/2
            //             = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
            //             = (transit + skew - transit + skew)/2
            //             = (2 * skew)/2 = skew
            long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
            // if (false) Log.d(TAG, "round trip: " + roundTripTime + " ms");
            // if (false) Log.d(TAG, "clock offset: " + clockOffset + " ms");

            // save our results - use the times on this side of the network latency
            // (response rather than request time)
            mNtpTime = responseTime + clockOffset;
            mNtpTimeReference = responseTicks;
            mRoundTripTime = roundTripTime;
        } catch (Exception e) {
            if (false) Log.d(TAG, "request time failed: " + e);
            return false;
        } finally {
            if (socket != null) {
                socket.close();
            }
        }

        return true;
    
private voidwriteTimeStamp(byte[] buffer, int offset, long time)
Writes system time (milliseconds since January 1, 1970) as an NTP time stamp at the given offset in the buffer.

        long seconds = time / 1000L;
        long milliseconds = time - seconds * 1000L;
        seconds += OFFSET_1900_TO_1970;

        // write seconds in big endian format
        buffer[offset++] = (byte)(seconds >> 24);
        buffer[offset++] = (byte)(seconds >> 16);
        buffer[offset++] = (byte)(seconds >> 8);
        buffer[offset++] = (byte)(seconds >> 0);

        long fraction = milliseconds * 0x100000000L / 1000L;
        // write fraction in big endian format
        buffer[offset++] = (byte)(fraction >> 24);
        buffer[offset++] = (byte)(fraction >> 16);
        buffer[offset++] = (byte)(fraction >> 8);
        // low order bits should be random data
        buffer[offset++] = (byte)(Math.random() * 255.0);