001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.net.time;
019
020import java.io.IOException;
021import java.net.DatagramPacket;
022import java.net.InetAddress;
023import java.util.Date;
024
025import org.apache.commons.net.DatagramSocketClient;
026
027/***
028 * The TimeUDPClient class is a UDP implementation of a client for the
029 * Time protocol described in RFC 868.  To use the class, merely
030 * open a local datagram socket with
031 * {@link org.apache.commons.net.DatagramSocketClient#open  open }
032 * and call {@link #getTime  getTime } or
033 * {@link #getTime  getDate } to retrieve the time. Then call
034 * {@link org.apache.commons.net.DatagramSocketClient#close  close }
035 * to close the connection properly.  Unlike
036 * {@link org.apache.commons.net.time.TimeTCPClient},
037 * successive calls to {@link #getTime  getTime } or
038 * {@link #getDate  getDate } are permitted
039 * without re-establishing a connection.  That is because UDP is a
040 * connectionless protocol and the Time protocol is stateless.
041 *
042 *
043 * @see TimeTCPClient
044 ***/
045
046public final class TimeUDPClient extends DatagramSocketClient
047{
048    /*** The default time port.  It is set to 37 according to RFC 868. ***/
049    public static final int DEFAULT_PORT = 37;
050
051    /***
052     * The number of seconds between 00:00 1 January 1900 and
053     * 00:00 1 January 1970.  This value can be useful for converting
054     * time values to other formats.
055     ***/
056    public static final long SECONDS_1900_TO_1970 = 2208988800L;
057
058    private final byte[] __dummyData = new byte[1];
059    private final byte[] __timeData = new byte[4];
060
061    /***
062     * Retrieves the time from the specified server and port and
063     * returns it. The time is the number of seconds since
064     * 00:00 (midnight) 1 January 1900 GMT, as specified by RFC 868.
065     * This method reads the raw 32-bit big-endian
066     * unsigned integer from the server, converts it to a Java long, and
067     * returns the value.
068     *
069     * @param host The address of the server.
070     * @param port The port of the service.
071     * @return The time value retrieved from the server.
072     * @throws IOException If an error occurs while retrieving the time.
073     ***/
074    public long getTime(InetAddress host, int port) throws IOException
075    {
076        long time;
077        DatagramPacket sendPacket, receivePacket;
078
079        sendPacket =
080            new DatagramPacket(__dummyData, __dummyData.length, host, port);
081        receivePacket = new DatagramPacket(__timeData, __timeData.length);
082
083        _socket_.send(sendPacket);
084        _socket_.receive(receivePacket);
085
086        time = 0L;
087        time |= (((__timeData[0] & 0xff) << 24) & 0xffffffffL);
088        time |= (((__timeData[1] & 0xff) << 16) & 0xffffffffL);
089        time |= (((__timeData[2] & 0xff) << 8) & 0xffffffffL);
090        time |= ((__timeData[3] & 0xff) & 0xffffffffL);
091
092        return time;
093    }
094
095    /*** Same as <code> getTime(host, DEFAULT_PORT); </code>
096     * @param host the time server
097     * @return the time returned from the server
098     * @throws IOException on error
099     ***/
100    public long getTime(InetAddress host) throws IOException
101    {
102        return getTime(host, DEFAULT_PORT);
103    }
104
105
106    /***
107     * Retrieves the time from the server and returns a Java Date
108     * containing the time converted to the local timezone.
109     *
110     * @param host The address of the server.
111     * @param port The port of the service.
112     * @return A Date value containing the time retrieved from the server
113     *     converted to the local timezone.
114     * @throws IOException  If an error occurs while fetching the time.
115     ***/
116    public Date getDate(InetAddress host, int port) throws IOException
117    {
118        return new Date((getTime(host, port) - SECONDS_1900_TO_1970)*1000L);
119    }
120
121
122    /*** Same as <code> getTime(host, DEFAULT_PORT); </code>
123     * @param host the time server
124     * @return the date
125     * @throws IOException on error
126     ***/
127    public Date getDate(InetAddress host) throws IOException
128    {
129        return new Date((getTime(host, DEFAULT_PORT) -
130                         SECONDS_1900_TO_1970)*1000L);
131    }
132
133}
134