FileDocCategorySizeDatePackage
TimeServer.javaAPI DocExample2853Sun Apr 28 15:07:42 BST 2002com.ronsoft.books.nio.channels

TimeServer.java

package com.ronsoft.books.nio.channels;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.DatagramChannel;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;

/**
 * Provide RFC 868 time service (http://www.ietf.org/rfc/rfc0868.txt).
 * This code implements an RFC 868 listener to provide time
 * service.  The defined port for time service is 37.  On most
 * unix systems, root privilege is required to bind to ports
 * below 1024.  You can either run this code as root or
 * provide another port number on the command line.  Use
 * "-p port#" with TimeClient if you choose an alternate port.
 *
 * Note: The familiar rdate command on unix will probably not work
 * with this server.  Most versions of rdate use TCP rather than UDP
 * to request the time.
 *
 * Created: April 2002
 * @author Ron Hitchens (ron@ronsoft.com)
 * @version $Id: TimeServer.java,v 1.1 2002/04/28 22:07:43 ron Exp $
 */
public class TimeServer
{
	private static final int DEFAULT_TIME_PORT = 37;
	private static final long DIFF_1900 = 2208988800L;

	// --------------------------------------------------------------

	protected DatagramChannel channel;

	public TimeServer (int port)
		throws Exception
	{
		this.channel = DatagramChannel.open();
		this.channel.socket().bind (new InetSocketAddress (port));

		System.out.println ("Listening on port " + port
			+ " for time requests");
	}

	public void listen() throws Exception
	{
		// allocate a buffer to hold a long value
		ByteBuffer longBuffer = ByteBuffer.allocate (8);

		// assure big-endian (network) byte order
		longBuffer.order (ByteOrder.BIG_ENDIAN);
		// zero the whole buffer to be sure
		longBuffer.putLong (0, 0);
		// position to first byte of the low-order 32 bits
		longBuffer.position (4);

		// slice the buffer, gives view of the low-order 32 bits
		ByteBuffer buffer = longBuffer.slice();	

		while (true) {
			buffer.clear();

			SocketAddress sa = this.channel.receive (buffer);

			if (sa == null) {
				continue;	// defensive programming
			}
			// ignore content of recived datagram per rfc 868

			System.out.println ("Time request from " + sa);

			buffer.clear();		// sets pos/limit correctly

			// set 64-bit value, slice buffer sees low 32 bits
			longBuffer.putLong (0,
				(System.currentTimeMillis() / 1000) + DIFF_1900);

			this.channel.send (buffer, sa);
		}
	}

	// --------------------------------------------------------------

	public static void main (String [] argv)
		throws Exception
	{
		int port = DEFAULT_TIME_PORT;

		if (argv.length > 0) {
			port = Integer.parseInt (argv [0]);
		}

		try {
			TimeServer server = new TimeServer (port);

			server.listen();
		} catch (SocketException e) {
			System.out.println ("Can't bind to port " + port
				+ ", try a different one");
			
		}
	}
}